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);
261 ullCurrentChunkSize >>= 32;
264 std::cout <<
"ckID=" << convertToString(ChunkID) <<
" ";
265 std::cout <<
"ckSize=" << ullCurrentChunkSize <<
" ";
266 std::cout <<
"bEndianNative=" << pFile->bEndianNative << std::endl;
268 ullNewChunkSize = ullCurrentChunkSize;
273 uint32_t uiNewChunkID = ChunkID;
274 if (ChunkID == CHUNK_ID_RIFF) {
276 if (pFile->bEndianNative) uiNewChunkID = CHUNK_ID_RIFX;
278 if (!pFile->bEndianNative) uiNewChunkID = CHUNK_ID_RIFX;
282 uint64_t ullNewChunkSize = this->ullNewChunkSize;
286 ullNewChunkSize <<= 32;
288 if (!pFile->bEndianNative) {
290 swapBytes_32(&ullNewChunkSize);
292 swapBytes_64(&ullNewChunkSize);
298 if (lseek(hWrite, filePos, SEEK_SET) != -1) {
299 write(hWrite, &uiNewChunkID, 4);
303 LARGE_INTEGER liFilePos;
304 liFilePos.QuadPart = filePos;
305 if (SetFilePointerEx(hWrite, liFilePos, NULL, FILE_BEGIN)) {
306 DWORD dwBytesWritten;
307 WriteFile(hWrite, &uiNewChunkID, 4, &dwBytesWritten, NULL);
308 WriteFile(hWrite, &ullNewChunkSize, pFile->
FileOffsetSize, &dwBytesWritten, NULL);
311 if (!fseeko(hWrite, filePos, SEEK_SET)) {
312 fwrite(&uiNewChunkID, 4, 1, hWrite);
323 return convertToString(ChunkID);
336 const std::thread::id tid = std::this_thread::get_id();
337 return chunkPos.byThread[tid];
347 const std::thread::id tid = std::this_thread::get_id();
348 std::lock_guard<std::mutex> lock(chunkPos.mutex);
349 return chunkPos.byThread[tid];
359 return ullStartPos +
GetPos();
377 std::cout <<
"Chunk::SetPos(file_offset_t,stream_whence_t)" << std::endl;
379 std::lock_guard<std::mutex> lock(chunkPos.mutex);
386 pos = ullCurrentChunkSize - 1 - Where;
388 case stream_backward:
391 case stream_start:
default:
395 if (pos > ullCurrentChunkSize) pos = ullCurrentChunkSize;
412 std::cout <<
"Chunk::Remainingbytes()=" << ullCurrentChunkSize - ullPos << std::endl;
415 return (ullCurrentChunkSize > pos) ? ullCurrentChunkSize - pos : 0;
426 return CHUNK_HEADER_SIZE(fileOffsetSize) +
446 std::cout <<
"Chunk::GetState()" << std::endl;
451 if (!_isValidHandle(hRead))
452 return stream_closed;
455 if (pos < ullCurrentChunkSize)
return stream_ready;
456 else return stream_end_reached;
477 std::cout <<
"Chunk::Read(void*,file_offset_t,file_offset_t)" << std::endl;
481 if (pos >= ullCurrentChunkSize)
return 0;
482 if (pos + WordCount * WordSize >= ullCurrentChunkSize)
483 WordCount = (ullCurrentChunkSize - pos) / WordSize;
488 if (lseek(hRead, ullStartPos + pos, SEEK_SET) < 0)
return 0;
489 ssize_t readWords = read(hRead, pData, WordCount * WordSize);
492 std::cerr <<
"POSIX read() failed: " << strerror(errno) << std::endl << std::flush;
496 readWords /= WordSize;
498 LARGE_INTEGER liFilePos;
499 liFilePos.QuadPart = ullStartPos + pos;
500 if (!SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN))
503 ReadFile(hRead, pData, WordCount * WordSize, &readWords, NULL);
504 if (readWords < 1)
return 0;
505 readWords /= WordSize;
507 if (fseeko(hRead, ullStartPos + pos, SEEK_SET))
return 0;
508 file_offset_t readWords = fread(pData, WordSize, WordCount, hRead);
510 if (!pFile->bEndianNative && WordSize != 1)
511 swapBytesOfWords(pData, readWords, WordSize);
512 SetPos(readWords * WordSize, stream_curpos);
535 if (io.Mode != stream_mode_read_write)
536 throw Exception(
"Cannot write data to chunk, file has to be opened in read+write mode first");
538 if (pos >= ullCurrentChunkSize || pos + WordCount * WordSize > ullCurrentChunkSize)
539 throw Exception(
"End of chunk reached while trying to write data");
540 if (!pFile->bEndianNative && WordSize != 1)
542 swapBytesOfWords(pData, WordCount, WordSize);
544 if (lseek(io.hWrite, ullStartPos + pos, SEEK_SET) < 0) {
545 throw Exception(
"Could not seek to position " + ToString(pos) +
546 " in chunk (" + ToString(ullStartPos + pos) +
" in file)");
548 ssize_t writtenWords = write(io.hWrite, pData, WordCount * WordSize);
549 if (writtenWords < 1)
throw Exception(
"POSIX IO Error while trying to write chunk data");
550 writtenWords /= WordSize;
552 LARGE_INTEGER liFilePos;
553 liFilePos.QuadPart = ullStartPos + pos;
554 if (!SetFilePointerEx(io.hWrite, liFilePos, NULL, FILE_BEGIN)) {
555 throw Exception(
"Could not seek to position " + ToString(pos) +
556 " in chunk (" + ToString(ullStartPos + pos) +
" in file)");
559 WriteFile(io.hWrite, pData, WordCount * WordSize, &writtenWords, NULL);
560 if (writtenWords < 1)
throw Exception(
"Windows IO Error while trying to write chunk data");
561 writtenWords /= WordSize;
563 if (fseeko(io.hWrite, ullStartPos + pos, SEEK_SET)) {
564 throw Exception(
"Could not seek to position " + ToString(pos) +
565 " in chunk (" + ToString(ullStartPos + pos) +
" in file)");
567 file_offset_t writtenWords = fwrite(pData, WordSize, WordCount, io.hWrite);
569 if (!pFile->bEndianNative && WordSize != 1)
571 swapBytesOfWords(pData, WordCount, WordSize);
572 SetPos(writtenWords * WordSize, stream_curpos);
579 if (readWords != WordCount)
throw RIFF::Exception(
"End of chunk data reached.");
597 std::cout <<
"Chunk::ReadInt8(int8_t*,file_offset_t)" << std::endl;
618 return Write(pData, WordCount, 1);
636 std::cout <<
"Chunk::ReadUint8(uint8_t*,file_offset_t)" << std::endl;
657 return Write(pData, WordCount, 1);
675 std::cout <<
"Chunk::ReadInt16(int16_t*,file_offset_t)" << std::endl;
696 return Write(pData, WordCount, 2);
714 std::cout <<
"Chunk::ReadUint16(uint16_t*,file_offset_t)" << std::endl;
735 return Write(pData, WordCount, 2);
753 std::cout <<
"Chunk::ReadInt32(int32_t*,file_offset_t)" << std::endl;
774 return Write(pData, WordCount, 4);
792 std::cout <<
"Chunk::ReadUint32(uint32_t*,file_offset_t)" << std::endl;
809 char* buf =
new char[size];
811 s.assign(buf, std::find(buf, buf + size,
'\0'));
831 return Write(pData, WordCount, 4);
844 std::cout <<
"Chunk::ReadInt8()" << std::endl;
861 std::cout <<
"Chunk::ReadUint8()" << std::endl;
879 std::cout <<
"Chunk::ReadInt16()" << std::endl;
897 std::cout <<
"Chunk::ReadUint16()" << std::endl;
915 std::cout <<
"Chunk::ReadInt32()" << std::endl;
933 std::cout <<
"Chunk::ReadUint32()" << std::endl;
963 if (!pChunkData && pFile->Filename !=
"" ) {
966 if (lseek(hRead, ullStartPos, SEEK_SET) == -1)
return NULL;
968 LARGE_INTEGER liFilePos;
969 liFilePos.QuadPart = ullStartPos;
970 if (!SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN))
return NULL;
972 if (fseeko(hRead, ullStartPos, SEEK_SET))
return NULL;
974 file_offset_t ullBufferSize = (ullCurrentChunkSize > ullNewChunkSize) ? ullCurrentChunkSize : ullNewChunkSize;
975 pChunkData =
new uint8_t[ullBufferSize];
976 if (!pChunkData)
return NULL;
977 memset(pChunkData, 0, ullBufferSize);
982 ReadFile(hRead, pChunkData,
GetSize(), &readWords, NULL);
988 return (pChunkData = NULL);
990 ullChunkDataSize = ullBufferSize;
991 }
else if (ullNewChunkSize > ullChunkDataSize) {
992 uint8_t* pNewBuffer =
new uint8_t[ullNewChunkSize];
993 if (!pNewBuffer)
throw Exception(
"Could not enlarge chunk data buffer to " + ToString(ullNewChunkSize) +
" bytes");
994 memset(pNewBuffer, 0 , ullNewChunkSize);
996 memcpy(pNewBuffer, pChunkData, ullChunkDataSize);
999 pChunkData = pNewBuffer;
1000 ullChunkDataSize = ullNewChunkSize;
1013 delete[] pChunkData;
1038 throw Exception(
"There is at least one empty chunk (zero size): " + __resolveChunkPath(
this));
1039 if ((NewSize >> 48) != 0)
1040 throw Exception(
"Unrealistic high chunk size detected: " + __resolveChunkPath(
this));
1041 if (ullNewChunkSize == NewSize)
return;
1042 ullNewChunkSize = NewSize;
1065 if (io.Mode != stream_mode_read_write)
1066 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
1074 lseek(io.hWrite, ullWritePos, SEEK_SET);
1075 if (write(io.hWrite, pChunkData, ullNewChunkSize) != ullNewChunkSize) {
1076 throw Exception(
"Writing Chunk data (from RAM) failed");
1078 #elif defined(WIN32)
1079 LARGE_INTEGER liFilePos;
1080 liFilePos.QuadPart = ullWritePos;
1081 SetFilePointerEx(io.hWrite, liFilePos, NULL, FILE_BEGIN);
1082 DWORD dwBytesWritten;
1083 WriteFile(io.hWrite, pChunkData, ullNewChunkSize, &dwBytesWritten, NULL);
1084 if (dwBytesWritten != ullNewChunkSize) {
1085 throw Exception(
"Writing Chunk data (from RAM) failed");
1088 fseeko(io.hWrite, ullWritePos, SEEK_SET);
1089 if (fwrite(pChunkData, 1, ullNewChunkSize, io.hWrite) != ullNewChunkSize) {
1090 throw Exception(
"Writing Chunk data (from RAM) failed");
1095 int8_t* pCopyBuffer =
new int8_t[4096];
1096 file_offset_t ullToMove = (ullNewChunkSize < ullCurrentChunkSize) ? ullNewChunkSize : ullCurrentChunkSize;
1098 DWORD iBytesMoved = 1;
1100 int iBytesMoved = 1;
1102 for (
file_offset_t ullOffset = 0; ullToMove > 0 && iBytesMoved > 0; ullOffset += iBytesMoved, ullToMove -= iBytesMoved) {
1103 iBytesMoved = (ullToMove < 4096) ?
int(ullToMove) : 4096;
1105 lseek(io.hRead, ullStartPos + ullCurrentDataOffset + ullOffset, SEEK_SET);
1106 iBytesMoved = (int) read(io.hRead, pCopyBuffer, (
size_t) iBytesMoved);
1107 lseek(io.hWrite, ullWritePos + ullOffset, SEEK_SET);
1108 iBytesMoved = (int) write(io.hWrite, pCopyBuffer, (
size_t) iBytesMoved);
1109 #elif defined(WIN32)
1110 LARGE_INTEGER liFilePos;
1111 liFilePos.QuadPart = ullStartPos + ullCurrentDataOffset + ullOffset;
1112 SetFilePointerEx(io.hRead, liFilePos, NULL, FILE_BEGIN);
1113 ReadFile(io.hRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1114 liFilePos.QuadPart = ullWritePos + ullOffset;
1115 SetFilePointerEx(io.hWrite, liFilePos, NULL, FILE_BEGIN);
1116 WriteFile(io.hWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1118 fseeko(io.hRead, ullStartPos + ullCurrentDataOffset + ullOffset, SEEK_SET);
1119 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved, io.hRead);
1120 fseeko(io.hWrite, ullWritePos + ullOffset, SEEK_SET);
1121 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved, io.hWrite);
1124 delete[] pCopyBuffer;
1125 if (iBytesMoved < 0)
throw Exception(
"Writing Chunk data (from file) failed");
1129 ullCurrentChunkSize = ullNewChunkSize;
1130 WriteHeader(ullOriginalPos);
1133 ullStartPos = ullOriginalPos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1136 if (pProgress && pProgress->
__private) {
1137 _FileProgress* fileProgress = (_FileProgress*) pProgress->
__private;
1138 fileProgress->advance(pProgress, ullNewChunkSize +
1143 if ((ullStartPos + ullNewChunkSize) % 2 != 0) {
1144 const char cPadByte = 0;
1146 lseek(io.hWrite, ullStartPos + ullNewChunkSize, SEEK_SET);
1147 write(io.hWrite, &cPadByte, 1);
1148 #elif defined(WIN32)
1149 LARGE_INTEGER liFilePos;
1150 liFilePos.QuadPart = ullStartPos + ullNewChunkSize;
1151 SetFilePointerEx(io.hWrite, liFilePos, NULL, FILE_BEGIN);
1152 DWORD dwBytesWritten;
1153 WriteFile(io.hWrite, &cPadByte, 1, &dwBytesWritten, NULL);
1155 fseeko(io.hWrite, ullStartPos + ullNewChunkSize, SEEK_SET);
1156 fwrite(&cPadByte, 1, 1, io.hWrite);
1158 return ullStartPos + ullNewChunkSize + 1;
1161 return ullStartPos + ullNewChunkSize;
1165 std::lock_guard<std::mutex> lock(chunkPos.mutex);
1166 chunkPos.ullPos = 0;
1167 chunkPos.byThread.clear();
1175 List::List(
File* pFile) :
Chunk(pFile) {
1177 std::cout <<
"List::List(File* pFile)" << std::endl;
1180 pSubChunksMap = NULL;
1183 List::List(File* pFile,
file_offset_t StartPos, List* Parent)
1184 : Chunk(pFile, StartPos, Parent) {
1186 std::cout <<
"List::List(File*,file_offset_t,List*)" << std::endl;
1189 pSubChunksMap = NULL;
1190 ReadHeader(StartPos);
1191 ullStartPos = StartPos + LIST_HEADER_SIZE(pFile->FileOffsetSize);
1194 List::List(File* pFile, List* pParent, uint32_t uiListID)
1195 : Chunk(pFile, pParent, CHUNK_ID_LIST, 0) {
1197 pSubChunksMap = NULL;
1198 ListType = uiListID;
1203 std::cout <<
"List::~List()" << std::endl;
1208 void List::DeleteChunkList() {
1210 ChunkList::iterator iter = pSubChunks->begin();
1211 ChunkList::iterator end = pSubChunks->end();
1212 while (iter != end) {
1219 if (pSubChunksMap) {
1220 delete pSubChunksMap;
1221 pSubChunksMap = NULL;
1235 if (!pSubChunks) LoadSubChunks();
1236 if (pos >= pSubChunks->size())
return NULL;
1237 return (*pSubChunks)[pos];
1253 std::cout <<
"List::GetSubChunk(uint32_t)" << std::endl;
1255 if (!pSubChunksMap) LoadSubChunks();
1256 return (*pSubChunksMap)[ChunkID];
1270 if (!pSubChunks) LoadSubChunks();
1271 if (pos >= pSubChunks->size())
return NULL;
1272 for (
size_t iCk = 0, iLst = 0; iCk < pSubChunks->size(); ++iCk) {
1273 Chunk* pChunk = (*pSubChunks)[iCk];
1274 if (pChunk->
GetChunkID() != CHUNK_ID_LIST)
continue;
1275 if (iLst == pos)
return (
List*) pChunk;
1294 std::cout <<
"List::GetSubList(uint32_t)" << std::endl;
1296 if (!pSubChunks) LoadSubChunks();
1297 ChunkList::iterator iter = pSubChunks->begin();
1298 ChunkList::iterator end = pSubChunks->end();
1299 while (iter != end) {
1300 if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
1322 std::cout <<
"List::GetFirstSubChunk()" << std::endl;
1324 if (!pSubChunks) LoadSubChunks();
1325 ChunksIterator = pSubChunks->begin();
1326 return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1341 std::cout <<
"List::GetNextSubChunk()" << std::endl;
1343 if (!pSubChunks)
return NULL;
1345 return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1361 std::cout <<
"List::GetFirstSubList()" << std::endl;
1363 if (!pSubChunks) LoadSubChunks();
1364 ListIterator = pSubChunks->begin();
1365 ChunkList::iterator end = pSubChunks->end();
1366 while (ListIterator != end) {
1367 if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST)
return (
List*) *ListIterator;
1385 std::cout <<
"List::GetNextSubList()" << std::endl;
1387 if (!pSubChunks)
return NULL;
1388 if (ListIterator == pSubChunks->end())
return NULL;
1390 ChunkList::iterator end = pSubChunks->end();
1391 while (ListIterator != end) {
1392 if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST)
return (
List*) *ListIterator;
1402 if (!pSubChunks) LoadSubChunks();
1403 return pSubChunks->size();
1412 if (!pSubChunks) LoadSubChunks();
1413 ChunkList::iterator iter = pSubChunks->begin();
1414 ChunkList::iterator end = pSubChunks->end();
1415 while (iter != end) {
1416 if ((*iter)->GetChunkID() == ChunkID) {
1437 if (!pSubChunks) LoadSubChunks();
1438 ChunkList::iterator iter = pSubChunks->begin();
1439 ChunkList::iterator end = pSubChunks->end();
1440 while (iter != end) {
1441 if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
1464 if (ullBodySize == 0)
throw Exception(
"Chunk body size must be at least 1 byte");
1465 if (!pSubChunks) LoadSubChunks();
1467 Chunk* pNewChunk =
new Chunk(pFile,
this, uiChunkID, 0);
1468 pSubChunks->push_back(pNewChunk);
1469 (*pSubChunksMap)[uiChunkID] = pNewChunk;
1470 pNewChunk->
Resize(ullBodySize);
1473 pFile->nDataChunkCount++;
1490 if (!pSubChunks) LoadSubChunks();
1491 for (
size_t i = 0; i < pSubChunks->size(); ++i) {
1492 if ((*pSubChunks)[i] == pSrc) {
1493 pSubChunks->erase(pSubChunks->begin() + i);
1494 ChunkList::iterator iter =
1495 find(pSubChunks->begin(), pSubChunks->end(), pDst);
1496 pSubChunks->insert(iter, pSrc);
1511 if (pNewParent ==
this || !pNewParent)
return;
1512 if (!pSubChunks) LoadSubChunks();
1513 if (!pNewParent->pSubChunks) pNewParent->LoadSubChunks();
1514 ChunkList::iterator iter =
1515 find(pSubChunks->begin(), pSubChunks->end(), pSrc);
1516 if (iter == pSubChunks->end())
return;
1517 pSubChunks->erase(iter);
1518 pNewParent->pSubChunks->push_back(pSrc);
1520 if ((*pSubChunksMap)[pSrc->
GetChunkID()] == pSrc) {
1523 ChunkList::iterator iter = pSubChunks->begin();
1524 ChunkList::iterator end = pSubChunks->end();
1525 for (; iter != end; ++iter) {
1526 if ((*iter)->GetChunkID() == pSrc->
GetChunkID()) {
1527 (*pSubChunksMap)[pSrc->
GetChunkID()] = *iter;
1533 if (!(*pNewParent->pSubChunksMap)[pSrc->
GetChunkID()])
1534 (*pNewParent->pSubChunksMap)[pSrc->
GetChunkID()] = pSrc;
1547 if (!pSubChunks) LoadSubChunks();
1549 List* pNewListChunk =
new List(pFile,
this, uiListType);
1550 pSubChunks->push_back(pNewListChunk);
1551 (*pSubChunksMap)[CHUNK_ID_LIST] = pNewListChunk;
1554 pFile->nListChunkCount++;
1556 return pNewListChunk;
1570 if (!pSubChunks) LoadSubChunks();
1571 ChunkList::iterator iter =
1572 find(pSubChunks->begin(), pSubChunks->end(), pSubChunk);
1573 if (iter == pSubChunks->end())
return;
1574 pSubChunks->erase(iter);
1576 if (
dynamic_cast<List*
>(pSubChunk))
1577 pFile->nListChunkCount--;
1579 pFile->nDataChunkCount--;
1581 if ((*pSubChunksMap)[pSubChunk->
GetChunkID()] == pSubChunk) {
1582 pSubChunksMap->erase(pSubChunk->
GetChunkID());
1584 ChunkList::iterator iter = pSubChunks->begin();
1585 ChunkList::iterator end = pSubChunks->end();
1586 for (; iter != end; ++iter) {
1587 if ((*iter)->GetChunkID() == pSubChunk->
GetChunkID()) {
1588 (*pSubChunksMap)[pSubChunk->
GetChunkID()] = *iter;
1604 if (!pSubChunks) LoadSubChunks();
1606 ChunkList::iterator iter = pSubChunks->begin();
1607 ChunkList::iterator end = pSubChunks->end();
1608 for (; iter != end; ++iter)
1609 size += (*iter)->RequiredPhysicalSize(fileOffsetSize);
1615 std::cout <<
"List::Readheader(file_offset_t) ";
1617 Chunk::ReadHeader(filePos);
1618 if (ullCurrentChunkSize < 4)
return;
1619 ullNewChunkSize = ullCurrentChunkSize -= 4;
1624 lseek(hRead, filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize), SEEK_SET);
1625 read(hRead, &ListType, 4);
1626 #elif defined(WIN32)
1627 LARGE_INTEGER liFilePos;
1628 liFilePos.QuadPart = filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1629 SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN);
1631 ReadFile(hRead, &ListType, 4, &dwBytesRead, NULL);
1633 fseeko(hRead, filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize), SEEK_SET);
1634 fread(&ListType, 4, 1, hRead);
1637 std::cout <<
"listType=" << convertToString(ListType) << std::endl;
1639 if (!pFile->bEndianNative) {
1646 ullNewChunkSize += 4;
1647 Chunk::WriteHeader(filePos);
1648 ullNewChunkSize -= 4;
1653 lseek(hWrite, filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize), SEEK_SET);
1654 write(hWrite, &ListType, 4);
1655 #elif defined(WIN32)
1656 LARGE_INTEGER liFilePos;
1657 liFilePos.QuadPart = filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1658 SetFilePointerEx(hWrite, liFilePos, NULL, FILE_BEGIN);
1659 DWORD dwBytesWritten;
1660 WriteFile(hWrite, &ListType, 4, &dwBytesWritten, NULL);
1662 fseeko(hWrite, filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize), SEEK_SET);
1663 fwrite(&ListType, 4, 1, hWrite);
1667 void List::LoadSubChunks(progress_t* pProgress) {
1669 std::cout <<
"List::LoadSubChunks()";
1672 pSubChunks =
new ChunkList();
1673 pSubChunksMap =
new ChunkMap();
1676 if (!_isValidHandle(hRead))
return;
1685 if (
Read(&ckid, 4, 1) != 4)
1686 throw Exception(
"LoadSubChunks(): Failed reading RIFF chunk ID");
1688 std::cout <<
" ckid=" << convertToString(ckid) << std::endl;
1691 if (ckid == CHUNK_ID_LIST) {
1692 ck =
new RIFF::List(pFile, ullStartPos + pos - 4,
this);
1695 pFile->nListChunkCount++;
1698 ck =
new RIFF::Chunk(pFile, ullStartPos + pos - 4,
this);
1701 pFile->nDataChunkCount++;
1703 pSubChunks->push_back(ck);
1704 (*pSubChunksMap)[ckid] = ck;
1710 __notify_progress(pProgress, 1.0);
1713 void List::LoadSubChunksRecursively(progress_t* pProgress) {
1714 const bool alreadyLoaded = pSubChunks;
1720 progress_t subprogress;
1721 __divide_progress(pProgress, &subprogress, n, i);
1723 pList->LoadSubChunksRecursively(&subprogress);
1725 pList->LoadSubChunksRecursively(NULL);
1727 if (pProgress && !alreadyLoaded)
1728 __notify_progress(pProgress, 1.0);
1750 if (pFile->
GetMode() != stream_mode_read_write)
1751 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
1755 for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter) {
1756 ullWritePos = (*iter)->WriteChunk(ullWritePos, ullCurrentDataOffset, pProgress);
1761 ullCurrentChunkSize = ullNewChunkSize = ullWritePos - ullOriginalPos - LIST_HEADER_SIZE(pFile->
FileOffsetSize);
1762 WriteHeader(ullOriginalPos);
1765 ullStartPos = ullOriginalPos + LIST_HEADER_SIZE(pFile->
FileOffsetSize);
1767 if (pProgress && pProgress->
__private) {
1768 _FileProgress* fileProgress = (_FileProgress*) pProgress->
__private;
1769 fileProgress->advance(pProgress,
1779 for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter) {
1780 (*iter)->__resetPos();
1789 return convertToString(ListType);
1815 io.isPerThread =
false;
1816 io.hRead = io.hWrite = RIFF_INVALID_FILE_HANDLE;
1817 io.Mode = stream_mode_closed;
1818 bEndianNative =
true;
1819 ListType = FileType;
1821 nDataChunkCount = 0;
1822 nListChunkCount = 0;
1839 std::cout <<
"File::File("<<path<<
")" << std::endl;
1841 bEndianNative =
true;
1843 nDataChunkCount = 0;
1844 nListChunkCount = 0;
1846 __openExistingFile(path);
1847 if (ChunkID != CHUNK_ID_RIFF && ChunkID != CHUNK_ID_RIFX) {
1884 :
List(this), Filename(path), bIsNewFile(false), Layout(layout),
1885 FileOffsetPreference(fileOffsetSize)
1889 throw Exception(
"Invalid RIFF::offset_size_t");
1891 nDataChunkCount = 0;
1892 nListChunkCount = 0;
1894 __openExistingFile(path, &FileType);
1912 void File::__openExistingFile(
const String& path, uint32_t* FileType) {
1913 io.isPerThread =
false;
1915 io.hRead = io.hWrite = open(path.c_str(), O_RDONLY | O_NONBLOCK);
1916 if (!_isValidHandle(io.hRead)) {
1917 String sError = strerror(errno);
1920 #elif defined(WIN32)
1921 io.hRead = io.hWrite = CreateFile(
1922 path.c_str(), GENERIC_READ,
1923 FILE_SHARE_READ | FILE_SHARE_WRITE,
1924 NULL, OPEN_EXISTING,
1925 FILE_ATTRIBUTE_NORMAL |
1926 FILE_FLAG_RANDOM_ACCESS, NULL
1928 if (!_isValidHandle(io.hRead)) {
1932 io.hRead = io.hWrite = fopen(path.c_str(),
"rb");
1933 if (!_isValidHandle(io.hRead))
1936 io.Mode = stream_mode_read;
1946 if (FileType && ChunkID != *FileType)
1954 if (
Read(&ckid, 4, 1) != 4) {
1955 throw RIFF::Exception(
"Invalid file header ID (premature end of header)");
1956 }
else if (ckid != *FileType) {
1957 String s =
" (expected '" + convertToString(*FileType) +
"' but got '" + convertToString(ckid) +
"')";
1967 String File::GetFileName()
const {
1971 void File::SetFileName(
const String& path) {
1983 File::HandlePair& File::FileHandlePairUnsafeRef() {
1984 if (io.byThread.empty())
return io;
1985 const std::thread::id tid = std::this_thread::get_id();
1986 const auto it = io.byThread.find(tid);
1987 return (it != io.byThread.end()) ?
1989 io.byThread[tid] = {
1991 RIFF_INVALID_FILE_HANDLE,
1992 RIFF_INVALID_FILE_HANDLE,
2004 std::lock_guard<std::mutex> lock(io.mutex);
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,
2065 bool bResetPos =
false;
2066 bool res = SetModeInternal(NewMode, &bResetPos);
2075 bool File::SetModeInternal(
stream_mode_t NewMode,
bool* pResetPos) {
2076 std::lock_guard<std::mutex> lock(io.mutex);
2077 HandlePair& io = FileHandlePairUnsafeRef();
2078 if (NewMode != io.Mode) {
2080 case stream_mode_read:
2081 if (_isValidHandle(io.hRead)) _close(io.hRead);
2083 io.hRead = io.hWrite = open(Filename.c_str(), O_RDONLY | O_NONBLOCK);
2084 if (!_isValidHandle(io.hRead)) {
2085 String sError = strerror(errno);
2086 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode: " + sError);
2088 #elif defined(WIN32)
2089 io.hRead = io.hWrite = CreateFile(
2090 Filename.c_str(), GENERIC_READ,
2091 FILE_SHARE_READ | FILE_SHARE_WRITE,
2092 NULL, OPEN_EXISTING,
2093 FILE_ATTRIBUTE_NORMAL |
2094 FILE_FLAG_RANDOM_ACCESS,
2097 if (!_isValidHandle(io.hRead)) {
2098 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode");
2101 io.hRead = io.hWrite = fopen(Filename.c_str(),
"rb");
2102 if (!_isValidHandle(io.hRead))
2103 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode");
2107 case stream_mode_read_write:
2108 if (_isValidHandle(io.hRead)) _close(io.hRead);
2110 io.hRead = io.hWrite = open(Filename.c_str(), O_RDWR | O_NONBLOCK);
2111 if (!_isValidHandle(io.hRead)) {
2112 io.hRead = io.hWrite = open(Filename.c_str(), O_RDONLY | O_NONBLOCK);
2113 String sError = strerror(errno);
2114 throw Exception(
"Could not open file \"" + Filename +
"\" in read+write mode: " + sError);
2116 #elif defined(WIN32)
2117 io.hRead = io.hWrite = CreateFile(
2119 GENERIC_READ | GENERIC_WRITE,
2122 FILE_ATTRIBUTE_NORMAL |
2123 FILE_FLAG_RANDOM_ACCESS,
2126 if (!_isValidHandle(io.hRead)) {
2127 io.hRead = io.hWrite = CreateFile(
2128 Filename.c_str(), GENERIC_READ,
2129 FILE_SHARE_READ | FILE_SHARE_WRITE,
2130 NULL, OPEN_EXISTING,
2131 FILE_ATTRIBUTE_NORMAL |
2132 FILE_FLAG_RANDOM_ACCESS,
2135 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read+write mode");
2138 io.hRead = io.hWrite = fopen(Filename.c_str(),
"r+b");
2139 if (!_isValidHandle(io.hRead)) {
2140 io.hRead = io.hWrite = fopen(Filename.c_str(),
"rb");
2141 throw Exception(
"Could not open file \"" + Filename +
"\" in read+write mode");
2146 case stream_mode_closed:
2147 if (_isValidHandle(io.hRead)) _close(io.hRead);
2148 if (_isValidHandle(io.hWrite)) _close(io.hWrite);
2149 io.hRead = io.hWrite = RIFF_INVALID_FILE_HANDLE;
2152 throw Exception(
"Unknown file access mode");
2171 bEndianNative = Endian != endian_little;
2173 bEndianNative = Endian != endian_big;
2190 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
2192 const bool bNeedLoadSubChunks = !pSubChunks;
2198 __divide_progress(pProgress, &subprogress, 1.f, 0.f, 0.2f);
2200 LoadSubChunksRecursively(&subprogress);
2202 __notify_progress(&subprogress, 1.f);
2204 LoadSubChunksRecursively(NULL);
2207 SetMode(stream_mode_read_write);
2220 const Handle hRead = io.hRead;
2221 const Handle hWrite = io.hWrite;
2233 if (newFileSize > workingFileSize) {
2234 positiveSizeDiff = newFileSize - workingFileSize;
2239 __divide_progress(pProgress, &subprogress, 1.f,
2240 bNeedLoadSubChunks ? 0.2f : 0.f,
2241 bNeedLoadSubChunks ? 0.7f : 0.6f);
2244 ResizeFile(newFileSize);
2247 int8_t* pCopyBuffer =
new int8_t[4096];
2249 DWORD iBytesMoved = 1;
2251 ssize_t iBytesMoved = 1;
2253 for (
file_offset_t ullPos = workingFileSize, iNotif = 0; iBytesMoved > 0; ++iNotif) {
2254 iBytesMoved = (ullPos < 4096) ? ullPos : 4096;
2255 ullPos -= iBytesMoved;
2257 lseek(hRead, ullPos, SEEK_SET);
2258 iBytesMoved = read(hRead, pCopyBuffer, iBytesMoved);
2259 lseek(hWrite, ullPos + positiveSizeDiff, SEEK_SET);
2260 iBytesMoved = write(hWrite, pCopyBuffer, iBytesMoved);
2261 #elif defined(WIN32)
2262 LARGE_INTEGER liFilePos;
2263 liFilePos.QuadPart = ullPos;
2264 SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN);
2265 ReadFile(hRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
2266 liFilePos.QuadPart = ullPos + positiveSizeDiff;
2267 SetFilePointerEx(hWrite, liFilePos, NULL, FILE_BEGIN);
2268 WriteFile(hWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
2270 fseeko(hRead, ullPos, SEEK_SET);
2271 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved, hRead);
2272 fseeko(hWrite, ullPos + positiveSizeDiff, SEEK_SET);
2273 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved, hWrite);
2275 if (pProgress && !(iNotif % 8) && iBytesMoved > 0)
2276 __notify_progress(&subprogress,
float(workingFileSize - ullPos) /
float(workingFileSize));
2278 delete[] pCopyBuffer;
2279 if (iBytesMoved < 0)
throw Exception(
"Could not modify file while trying to enlarge it");
2282 __notify_progress(&subprogress, 1.f);
2289 _FileProgress fileProgress = { 0, newFileSize };
2291 __divide_progress(pProgress, &subprogress, 1.f,
2292 bNeedLoadSubChunks ? 0.7f : 0.6f, 1.f);
2297 const file_offset_t finalActualSize = __GetFileSize(hWrite);
2300 __notify_progress(&subprogress, 1.f);
2303 if (finalSize < finalActualSize) ResizeFile(finalSize);
2306 __notify_progress(pProgress, 1.0);
2329 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
2331 const bool bNeedLoadSubChunks = !pSubChunks;
2337 __divide_progress(pProgress, &subprogress, 1.f, 0.f, 0.3f);
2339 LoadSubChunksRecursively(&subprogress);
2341 if (bNeedLoadSubChunks)
2342 __notify_progress(&subprogress, 1.f);
2344 LoadSubChunksRecursively(NULL);
2346 if (!bIsNewFile)
SetMode(stream_mode_read);
2349 std::lock_guard<std::mutex> lock(io.mutex);
2350 HandlePair& io = FileHandlePairUnsafeRef();
2354 io.hWrite = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
2355 if (!_isValidHandle(io.hWrite)) {
2356 io.hWrite = io.hRead;
2357 String sError = strerror(errno);
2358 throw Exception(
"Could not open file \"" + path +
"\" for writing: " + sError);
2360 #elif defined(WIN32)
2361 io.hWrite = CreateFile(
2362 path.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
2363 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL |
2364 FILE_FLAG_RANDOM_ACCESS, NULL
2366 if (!_isValidHandle(io.hWrite)) {
2367 io.hWrite = io.hRead;
2368 throw Exception(
"Could not open file \"" + path +
"\" for writing");
2371 io.hWrite = fopen(path.c_str(),
"w+b");
2372 if (!_isValidHandle(io.hWrite)) {
2373 io.hWrite = io.hRead;
2374 throw Exception(
"Could not open file \"" + path +
"\" for writing");
2377 io.Mode = stream_mode_read_write;
2392 __divide_progress(pProgress, &subprogress, 1.f,
2393 bNeedLoadSubChunks ? 0.3f : 0.f, 1.f);
2394 _FileProgress fileProgress = { 0, newFileSize };
2397 ullTotalSize =
WriteChunk(0, 0, &subprogress);
2399 __notify_progress(&subprogress, 1.f);
2406 if (ullActualSize > ullTotalSize) ResizeFile(ullTotalSize);
2409 std::lock_guard<std::mutex> lock(io.mutex);
2410 HandlePair& io = FileHandlePairUnsafeRef();
2412 if (_isValidHandle(io.hWrite)) _close(io.hWrite);
2413 io.hWrite = io.hRead;
2420 SetMode(stream_mode_read_write);
2423 __notify_progress(pProgress, 1.0);
2429 if (ftruncate(hWrite, ullNewSize) < 0)
2430 throw Exception(
"Could not resize file \"" + Filename +
"\"");
2431 #elif defined(WIN32)
2432 LARGE_INTEGER liFilePos;
2433 liFilePos.QuadPart = ullNewSize;
2435 !SetFilePointerEx(hWrite, liFilePos, NULL, FILE_BEGIN) ||
2436 !SetEndOfFile(hWrite)
2437 )
throw Exception(
"Could not resize file \"" + Filename +
"\"");
2439 # error Sorry, this version of libgig only supports POSIX and Windows systems yet.
2440 # error Reason: portable implementation of RIFF::File::ResizeFile() is missing (yet)!
2446 std::cout <<
"File::~File()" << std::endl;
2459 void File::Cleanup() {
2461 for (
auto it = io.byThread.begin(); it != io.byThread.end(); ++it) {
2462 _close(it->second.hRead);
2481 size = __GetFileSize(hRead);
2523 switch (fileOffsetSize) {
2533 default:
throw Exception(
"Internal error: Invalid RIFF::offset_size_t");
2539 switch (FileOffsetPreference) {
2541 return (fileSize >> 32) ? 8 : 4;
2547 throw Exception(
"Internal error: Invalid RIFF::offset_size_t");
2626 return io.isPerThread;
2645 std::lock_guard<std::mutex> lock(io.mutex);
2646 if (!io.byThread.empty() == enable)
return;
2647 io.isPerThread = enable;
2649 const std::thread::id tid = std::this_thread::get_id();
2650 io.byThread[tid] = io;
2653 for (
auto it = io.byThread.begin(); it != io.byThread.end(); ++it) {
2654 if (it == io.byThread.begin()) {
2655 io.hRead = it->second.hRead;
2656 io.hWrite = it->second.hWrite;
2658 _close(it->second.hRead);
2659 _close(it->second.hWrite);
2662 io.byThread.clear();
2675 return nDataChunkCount;
2687 return nListChunkCount;
2703 return nDataChunkCount + nListChunkCount;
2708 struct stat filestat;
2709 if (fstat(hFile, &filestat) == -1)
2710 throw Exception(
"POSIX FS error: could not determine file size");
2711 return filestat.st_size;
2713 #elif defined(WIN32)
2716 if (!GetFileSizeEx(hFile, &size))
2717 throw Exception(
"Windows FS error: could not determine file size");
2718 return size.QuadPart;
2722 off_t curpos = ftello(hFile);
2723 if (fseeko(hFile, 0, SEEK_END) == -1)
2724 throw Exception(
"FS error: could not determine file size");
2725 off_t size = ftello(hFile);
2726 fseeko(hFile, curpos, SEEK_SET);
2735 Exception::Exception() {
2738 Exception::Exception(String format, ...) {
2740 va_start(arg, format);
2741 Message = assemble(format, arg);
2745 Exception::Exception(String format, va_list arg) {
2746 Message = assemble(format, arg);
2749 Exception::~Exception() {
2752 void Exception::PrintMessage()
const {
2753 std::cout <<
"RIFF::Exception: " << Message << std::endl;
2756 String Exception::assemble(String format, va_list arg) {
2758 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!