42 static String __resolveChunkPath(Chunk* pCk) {
44 for (Chunk* pChunk = pCk; pChunk; pChunk = pChunk->GetParent()) {
45 if (pChunk->GetChunkID() == CHUNK_ID_LIST) {
46 List* pList = (List*) pChunk;
47 sPath =
"->'" + pList->GetListTypeString() +
"'" + sPath;
49 sPath =
"->'" + pChunk->GetChunkIDString() +
"'" + sPath;
60 progress_t::progress_t() {
75 std::vector<progress_t> v;
76 for (
int i = 0; i < iSubtasks; ++i) {
78 __divide_progress(
this, &p, iSubtasks, i);
108 for (
int i = 0; i < vSubTaskPortions.size(); ++i)
109 fTotal += vSubTaskPortions[i];
111 float fLow = 0.f, fHigh = 0.f;
112 std::vector<progress_t> v;
113 for (
int i = 0; i < vSubTaskPortions.size(); ++i) {
115 fHigh = vSubTaskPortions[i];
117 __divide_progress(
this, &p, fTotal, fLow, fHigh);
128 Chunk::Chunk(
File* pFile) {
130 std::cout <<
"Chunk::Chunk(File* pFile)" << std::endl;
135 ullCurrentChunkSize = 0;
137 ullChunkDataSize = 0;
138 ChunkID = CHUNK_ID_RIFF;
142 Chunk::Chunk(File* pFile,
file_offset_t StartPos, List* Parent) {
144 std::cout <<
"Chunk::Chunk(File*,file_offset_t,List*),StartPos=" << StartPos << std::endl;
147 ullStartPos = StartPos + CHUNK_HEADER_SIZE(pFile->FileOffsetSize);
151 ullCurrentChunkSize = 0;
153 ullChunkDataSize = 0;
154 ReadHeader(StartPos);
157 Chunk::Chunk(File* pFile, List* pParent, uint32_t uiChunkID,
file_offset_t ullBodySize) {
160 this->pParent = pParent;
164 ullChunkDataSize = 0;
165 ullCurrentChunkSize = 0;
166 ullNewChunkSize = ullBodySize;
170 if (pChunkData)
delete[] pChunkData;
175 std::cout <<
"Chunk::Readheader(" << filePos <<
") ";
178 ullNewChunkSize = ullCurrentChunkSize = 0;
180 if (lseek(pFile->
hFileRead, filePos, SEEK_SET) != -1) {
184 LARGE_INTEGER liFilePos;
185 liFilePos.QuadPart = filePos;
186 if (SetFilePointerEx(pFile->
hFileRead, liFilePos, NULL, FILE_BEGIN)) {
188 ReadFile(pFile->
hFileRead, &ChunkID, 4, &dwBytesRead, NULL);
191 if (!fseeko(pFile->
hFileRead, filePos, SEEK_SET)) {
196 if (ChunkID == CHUNK_ID_RIFF) {
197 pFile->bEndianNative =
false;
200 if (ChunkID == CHUNK_ID_RIFX) {
201 pFile->bEndianNative =
false;
202 ChunkID = CHUNK_ID_RIFF;
205 if (!pFile->bEndianNative) {
208 swapBytes_32(&ullCurrentChunkSize);
210 swapBytes_64(&ullCurrentChunkSize);
213 std::cout <<
"ckID=" << convertToString(ChunkID) <<
" ";
214 std::cout <<
"ckSize=" << ullCurrentChunkSize <<
" ";
215 std::cout <<
"bEndianNative=" << pFile->bEndianNative << std::endl;
217 ullNewChunkSize = ullCurrentChunkSize;
222 uint32_t uiNewChunkID = ChunkID;
223 if (ChunkID == CHUNK_ID_RIFF) {
225 if (pFile->bEndianNative) uiNewChunkID = CHUNK_ID_RIFX;
227 if (!pFile->bEndianNative) uiNewChunkID = CHUNK_ID_RIFX;
231 uint64_t ullNewChunkSize = this->ullNewChunkSize;
232 if (!pFile->bEndianNative) {
234 swapBytes_32(&ullNewChunkSize);
236 swapBytes_64(&ullNewChunkSize);
240 if (lseek(pFile->
hFileWrite, filePos, SEEK_SET) != -1) {
245 LARGE_INTEGER liFilePos;
246 liFilePos.QuadPart = filePos;
247 if (SetFilePointerEx(pFile->
hFileWrite, liFilePos, NULL, FILE_BEGIN)) {
248 DWORD dwBytesWritten;
249 WriteFile(pFile->
hFileWrite, &uiNewChunkID, 4, &dwBytesWritten, NULL);
253 if (!fseeko(pFile->
hFileWrite, filePos, SEEK_SET)) {
254 fwrite(&uiNewChunkID, 4, 1, pFile->
hFileWrite);
265 return convertToString(ChunkID);
282 std::cout <<
"Chunk::SetPos(file_offset_t,stream_whence_t)" << std::endl;
289 ullPos = ullCurrentChunkSize - 1 - Where;
291 case stream_backward:
294 case stream_start:
default:
298 if (ullPos > ullCurrentChunkSize) ullPos = ullCurrentChunkSize;
314 std::cout <<
"Chunk::Remainingbytes()=" << ullCurrentChunkSize - ullPos << std::endl;
316 return (ullCurrentChunkSize > ullPos) ? ullCurrentChunkSize - ullPos : 0;
327 return CHUNK_HEADER_SIZE(fileOffsetSize) +
345 std::cout <<
"Chunk::GetState()" << std::endl;
348 if (pFile->
hFileRead == 0)
return stream_closed;
349 #elif defined (WIN32)
350 if (pFile->
hFileRead == INVALID_HANDLE_VALUE)
351 return stream_closed;
353 if (pFile->
hFileRead == NULL)
return stream_closed;
355 if (ullPos < ullCurrentChunkSize)
return stream_ready;
356 else return stream_end_reached;
376 std::cout <<
"Chunk::Read(void*,file_offset_t,file_offset_t)" << std::endl;
379 if (ullPos >= ullCurrentChunkSize)
return 0;
380 if (ullPos + WordCount * WordSize >= ullCurrentChunkSize) WordCount = (ullCurrentChunkSize - ullPos) / WordSize;
382 if (lseek(pFile->
hFileRead, ullStartPos + ullPos, SEEK_SET) < 0)
return 0;
383 ssize_t readWords = read(pFile->
hFileRead, pData, WordCount * WordSize);
386 std::cerr <<
"POSIX read() failed: " << strerror(errno) << std::endl << std::flush;
390 readWords /= WordSize;
392 LARGE_INTEGER liFilePos;
393 liFilePos.QuadPart = ullStartPos + ullPos;
394 if (!SetFilePointerEx(pFile->
hFileRead, liFilePos, NULL, FILE_BEGIN))
397 ReadFile(pFile->
hFileRead, pData, WordCount * WordSize, &readWords, NULL);
398 if (readWords < 1)
return 0;
399 readWords /= WordSize;
401 if (fseeko(pFile->
hFileRead, ullStartPos + ullPos, SEEK_SET))
return 0;
404 if (!pFile->bEndianNative && WordSize != 1) {
408 swapBytes_16((uint16_t*) pData + iWord);
412 swapBytes_32((uint32_t*) pData + iWord);
416 swapBytes_64((uint64_t*) pData + iWord);
420 swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
424 SetPos(readWords * WordSize, stream_curpos);
445 if (pFile->Mode != stream_mode_read_write)
446 throw Exception(
"Cannot write data to chunk, file has to be opened in read+write mode first");
447 if (ullPos >= ullCurrentChunkSize || ullPos + WordCount * WordSize > ullCurrentChunkSize)
448 throw Exception(
"End of chunk reached while trying to write data");
449 if (!pFile->bEndianNative && WordSize != 1) {
453 swapBytes_16((uint16_t*) pData + iWord);
457 swapBytes_32((uint32_t*) pData + iWord);
461 swapBytes_64((uint64_t*) pData + iWord);
465 swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
470 if (lseek(pFile->
hFileWrite, ullStartPos + ullPos, SEEK_SET) < 0) {
471 throw Exception(
"Could not seek to position " + ToString(ullPos) +
472 " in chunk (" + ToString(ullStartPos + ullPos) +
" in file)");
474 ssize_t writtenWords = write(pFile->
hFileWrite, pData, WordCount * WordSize);
475 if (writtenWords < 1)
throw Exception(
"POSIX IO Error while trying to write chunk data");
476 writtenWords /= WordSize;
478 LARGE_INTEGER liFilePos;
479 liFilePos.QuadPart = ullStartPos + ullPos;
480 if (!SetFilePointerEx(pFile->
hFileWrite, liFilePos, NULL, FILE_BEGIN)) {
481 throw Exception(
"Could not seek to position " + ToString(ullPos) +
482 " in chunk (" + ToString(ullStartPos + ullPos) +
" in file)");
485 WriteFile(pFile->
hFileWrite, pData, WordCount * WordSize, &writtenWords, NULL);
486 if (writtenWords < 1)
throw Exception(
"Windows IO Error while trying to write chunk data");
487 writtenWords /= WordSize;
489 if (fseeko(pFile->
hFileWrite, ullStartPos + ullPos, SEEK_SET)) {
490 throw Exception(
"Could not seek to position " + ToString(ullPos) +
491 " in chunk (" + ToString(ullStartPos + ullPos) +
" in file)");
495 SetPos(writtenWords * WordSize, stream_curpos);
502 if (readWords != WordCount)
throw RIFF::Exception(
"End of chunk data reached.");
519 std::cout <<
"Chunk::ReadInt8(int8_t*,file_offset_t)" << std::endl;
539 return Write(pData, WordCount, 1);
556 std::cout <<
"Chunk::ReadUint8(uint8_t*,file_offset_t)" << std::endl;
576 return Write(pData, WordCount, 1);
593 std::cout <<
"Chunk::ReadInt16(int16_t*,file_offset_t)" << std::endl;
613 return Write(pData, WordCount, 2);
630 std::cout <<
"Chunk::ReadUint16(uint16_t*,file_offset_t)" << std::endl;
650 return Write(pData, WordCount, 2);
667 std::cout <<
"Chunk::ReadInt32(int32_t*,file_offset_t)" << std::endl;
687 return Write(pData, WordCount, 4);
704 std::cout <<
"Chunk::ReadUint32(uint32_t*,file_offset_t)" << std::endl;
720 char* buf =
new char[size];
722 s.assign(buf, std::find(buf, buf + size,
'\0'));
741 return Write(pData, WordCount, 4);
753 std::cout <<
"Chunk::ReadInt8()" << std::endl;
769 std::cout <<
"Chunk::ReadUint8()" << std::endl;
786 std::cout <<
"Chunk::ReadInt16()" << std::endl;
803 std::cout <<
"Chunk::ReadUint16()" << std::endl;
820 std::cout <<
"Chunk::ReadInt32()" << std::endl;
837 std::cout <<
"Chunk::ReadUint32()" << std::endl;
866 if (!pChunkData && pFile->Filename !=
"" ) {
868 if (lseek(pFile->
hFileRead, ullStartPos, SEEK_SET) == -1)
return NULL;
870 LARGE_INTEGER liFilePos;
871 liFilePos.QuadPart = ullStartPos;
872 if (!SetFilePointerEx(pFile->
hFileRead, liFilePos, NULL, FILE_BEGIN))
return NULL;
874 if (fseeko(pFile->
hFileRead, ullStartPos, SEEK_SET))
return NULL;
876 file_offset_t ullBufferSize = (ullCurrentChunkSize > ullNewChunkSize) ? ullCurrentChunkSize : ullNewChunkSize;
877 pChunkData =
new uint8_t[ullBufferSize];
878 if (!pChunkData)
return NULL;
879 memset(pChunkData, 0, ullBufferSize);
890 return (pChunkData = NULL);
892 ullChunkDataSize = ullBufferSize;
893 }
else if (ullNewChunkSize > ullChunkDataSize) {
894 uint8_t* pNewBuffer =
new uint8_t[ullNewChunkSize];
895 if (!pNewBuffer)
throw Exception(
"Could not enlarge chunk data buffer to " + ToString(ullNewChunkSize) +
" bytes");
896 memset(pNewBuffer, 0 , ullNewChunkSize);
897 memcpy(pNewBuffer, pChunkData, ullChunkDataSize);
899 pChunkData = pNewBuffer;
900 ullChunkDataSize = ullNewChunkSize;
938 throw Exception(
"There is at least one empty chunk (zero size): " + __resolveChunkPath(
this));
939 if ((NewSize >> 48) != 0)
940 throw Exception(
"Unrealistic high chunk size detected: " + __resolveChunkPath(
this));
941 if (ullNewChunkSize == NewSize)
return;
942 ullNewChunkSize = NewSize;
962 if (pFile->Mode != stream_mode_read_write)
963 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
971 lseek(pFile->
hFileWrite, ullWritePos, SEEK_SET);
972 if (write(pFile->
hFileWrite, pChunkData, ullNewChunkSize) != ullNewChunkSize) {
973 throw Exception(
"Writing Chunk data (from RAM) failed");
976 LARGE_INTEGER liFilePos;
977 liFilePos.QuadPart = ullWritePos;
978 SetFilePointerEx(pFile->
hFileWrite, liFilePos, NULL, FILE_BEGIN);
979 DWORD dwBytesWritten;
980 WriteFile(pFile->
hFileWrite, pChunkData, ullNewChunkSize, &dwBytesWritten, NULL);
981 if (dwBytesWritten != ullNewChunkSize) {
982 throw Exception(
"Writing Chunk data (from RAM) failed");
985 fseeko(pFile->
hFileWrite, ullWritePos, SEEK_SET);
986 if (fwrite(pChunkData, 1, ullNewChunkSize, pFile->
hFileWrite) != ullNewChunkSize) {
987 throw Exception(
"Writing Chunk data (from RAM) failed");
992 int8_t* pCopyBuffer =
new int8_t[4096];
993 file_offset_t ullToMove = (ullNewChunkSize < ullCurrentChunkSize) ? ullNewChunkSize : ullCurrentChunkSize;
995 DWORD iBytesMoved = 1;
999 for (
file_offset_t ullOffset = 0; ullToMove > 0 && iBytesMoved > 0; ullOffset += iBytesMoved, ullToMove -= iBytesMoved) {
1000 iBytesMoved = (ullToMove < 4096) ?
int(ullToMove) : 4096;
1002 lseek(pFile->
hFileRead, ullStartPos + ullCurrentDataOffset + ullOffset, SEEK_SET);
1003 iBytesMoved = (int) read(pFile->
hFileRead, pCopyBuffer, (
size_t) iBytesMoved);
1004 lseek(pFile->
hFileWrite, ullWritePos + ullOffset, SEEK_SET);
1005 iBytesMoved = (int) write(pFile->
hFileWrite, pCopyBuffer, (
size_t) iBytesMoved);
1006 #elif defined(WIN32)
1007 LARGE_INTEGER liFilePos;
1008 liFilePos.QuadPart = ullStartPos + ullCurrentDataOffset + ullOffset;
1009 SetFilePointerEx(pFile->
hFileRead, liFilePos, NULL, FILE_BEGIN);
1010 ReadFile(pFile->
hFileRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1011 liFilePos.QuadPart = ullWritePos + ullOffset;
1012 SetFilePointerEx(pFile->
hFileWrite, liFilePos, NULL, FILE_BEGIN);
1013 WriteFile(pFile->
hFileWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1015 fseeko(pFile->
hFileRead, ullStartPos + ullCurrentDataOffset + ullOffset, SEEK_SET);
1016 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved, pFile->
hFileRead);
1017 fseeko(pFile->
hFileWrite, ullWritePos + ullOffset, SEEK_SET);
1018 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved, pFile->
hFileWrite);
1021 delete[] pCopyBuffer;
1022 if (iBytesMoved < 0)
throw Exception(
"Writing Chunk data (from file) failed");
1026 ullCurrentChunkSize = ullNewChunkSize;
1027 WriteHeader(ullOriginalPos);
1030 __notify_progress(pProgress, 1.0);
1033 ullStartPos = ullOriginalPos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1037 if ((ullStartPos + ullNewChunkSize) % 2 != 0) {
1038 const char cPadByte = 0;
1040 lseek(pFile->
hFileWrite, ullStartPos + ullNewChunkSize, SEEK_SET);
1042 #elif defined(WIN32)
1043 LARGE_INTEGER liFilePos;
1044 liFilePos.QuadPart = ullStartPos + ullNewChunkSize;
1045 SetFilePointerEx(pFile->
hFileWrite, liFilePos, NULL, FILE_BEGIN);
1046 DWORD dwBytesWritten;
1047 WriteFile(pFile->
hFileWrite, &cPadByte, 1, &dwBytesWritten, NULL);
1049 fseeko(pFile->
hFileWrite, ullStartPos + ullNewChunkSize, SEEK_SET);
1052 return ullStartPos + ullNewChunkSize + 1;
1055 return ullStartPos + ullNewChunkSize;
1067 List::List(
File* pFile) :
Chunk(pFile) {
1069 std::cout <<
"List::List(File* pFile)" << std::endl;
1072 pSubChunksMap = NULL;
1075 List::List(File* pFile,
file_offset_t StartPos, List* Parent)
1076 : Chunk(pFile, StartPos, Parent) {
1078 std::cout <<
"List::List(File*,file_offset_t,List*)" << std::endl;
1081 pSubChunksMap = NULL;
1082 ReadHeader(StartPos);
1083 ullStartPos = StartPos + LIST_HEADER_SIZE(pFile->FileOffsetSize);
1086 List::List(File* pFile, List* pParent, uint32_t uiListID)
1087 : Chunk(pFile, pParent, CHUNK_ID_LIST, 0) {
1089 pSubChunksMap = NULL;
1090 ListType = uiListID;
1095 std::cout <<
"List::~List()" << std::endl;
1100 void List::DeleteChunkList() {
1102 ChunkList::iterator iter = pSubChunks->begin();
1103 ChunkList::iterator end = pSubChunks->end();
1104 while (iter != end) {
1111 if (pSubChunksMap) {
1112 delete pSubChunksMap;
1113 pSubChunksMap = NULL;
1130 std::cout <<
"List::GetSubChunk(uint32_t)" << std::endl;
1132 if (!pSubChunksMap) LoadSubChunks();
1133 return (*pSubChunksMap)[ChunkID];
1149 std::cout <<
"List::GetSubList(uint32_t)" << std::endl;
1151 if (!pSubChunks) LoadSubChunks();
1152 ChunkList::iterator iter = pSubChunks->begin();
1153 ChunkList::iterator end = pSubChunks->end();
1154 while (iter != end) {
1155 if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
1175 std::cout <<
"List::GetFirstSubChunk()" << std::endl;
1177 if (!pSubChunks) LoadSubChunks();
1178 ChunksIterator = pSubChunks->begin();
1179 return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1192 std::cout <<
"List::GetNextSubChunk()" << std::endl;
1194 if (!pSubChunks)
return NULL;
1196 return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1210 std::cout <<
"List::GetFirstSubList()" << std::endl;
1212 if (!pSubChunks) LoadSubChunks();
1213 ListIterator = pSubChunks->begin();
1214 ChunkList::iterator end = pSubChunks->end();
1215 while (ListIterator != end) {
1216 if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST)
return (
List*) *ListIterator;
1232 std::cout <<
"List::GetNextSubList()" << std::endl;
1234 if (!pSubChunks)
return NULL;
1235 if (ListIterator == pSubChunks->end())
return NULL;
1237 ChunkList::iterator end = pSubChunks->end();
1238 while (ListIterator != end) {
1239 if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST)
return (
List*) *ListIterator;
1249 if (!pSubChunks) LoadSubChunks();
1250 return pSubChunks->size();
1259 if (!pSubChunks) LoadSubChunks();
1260 ChunkList::iterator iter = pSubChunks->begin();
1261 ChunkList::iterator end = pSubChunks->end();
1262 while (iter != end) {
1263 if ((*iter)->GetChunkID() == ChunkID) {
1284 if (!pSubChunks) LoadSubChunks();
1285 ChunkList::iterator iter = pSubChunks->begin();
1286 ChunkList::iterator end = pSubChunks->end();
1287 while (iter != end) {
1288 if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
1311 if (ullBodySize == 0)
throw Exception(
"Chunk body size must be at least 1 byte");
1312 if (!pSubChunks) LoadSubChunks();
1313 Chunk* pNewChunk =
new Chunk(pFile,
this, uiChunkID, 0);
1314 pSubChunks->push_back(pNewChunk);
1315 (*pSubChunksMap)[uiChunkID] = pNewChunk;
1316 pNewChunk->
Resize(ullBodySize);
1333 if (!pSubChunks) LoadSubChunks();
1334 pSubChunks->remove(pSrc);
1335 ChunkList::iterator iter = find(pSubChunks->begin(), pSubChunks->end(), pDst);
1336 pSubChunks->insert(iter, pSrc);
1348 if (pNewParent ==
this || !pNewParent)
return;
1349 if (!pSubChunks) LoadSubChunks();
1350 if (!pNewParent->pSubChunks) pNewParent->LoadSubChunks();
1351 pSubChunks->remove(pSrc);
1352 pNewParent->pSubChunks->push_back(pSrc);
1354 if ((*pSubChunksMap)[pSrc->
GetChunkID()] == pSrc) {
1357 ChunkList::iterator iter = pSubChunks->begin();
1358 ChunkList::iterator end = pSubChunks->end();
1359 for (; iter != end; ++iter) {
1360 if ((*iter)->GetChunkID() == pSrc->
GetChunkID()) {
1361 (*pSubChunksMap)[pSrc->
GetChunkID()] = *iter;
1367 if (!(*pNewParent->pSubChunksMap)[pSrc->
GetChunkID()])
1368 (*pNewParent->pSubChunksMap)[pSrc->
GetChunkID()] = pSrc;
1381 if (!pSubChunks) LoadSubChunks();
1382 List* pNewListChunk =
new List(pFile,
this, uiListType);
1383 pSubChunks->push_back(pNewListChunk);
1384 (*pSubChunksMap)[CHUNK_ID_LIST] = pNewListChunk;
1386 return pNewListChunk;
1400 if (!pSubChunks) LoadSubChunks();
1401 pSubChunks->remove(pSubChunk);
1402 if ((*pSubChunksMap)[pSubChunk->
GetChunkID()] == pSubChunk) {
1403 pSubChunksMap->erase(pSubChunk->
GetChunkID());
1405 ChunkList::iterator iter = pSubChunks->begin();
1406 ChunkList::iterator end = pSubChunks->end();
1407 for (; iter != end; ++iter) {
1408 if ((*iter)->GetChunkID() == pSubChunk->
GetChunkID()) {
1409 (*pSubChunksMap)[pSubChunk->
GetChunkID()] = *iter;
1425 if (!pSubChunks) LoadSubChunks();
1427 ChunkList::iterator iter = pSubChunks->begin();
1428 ChunkList::iterator end = pSubChunks->end();
1429 for (; iter != end; ++iter)
1430 size += (*iter)->RequiredPhysicalSize(fileOffsetSize);
1436 std::cout <<
"List::Readheader(file_offset_t) ";
1438 Chunk::ReadHeader(filePos);
1439 if (ullCurrentChunkSize < 4)
return;
1440 ullNewChunkSize = ullCurrentChunkSize -= 4;
1444 #elif defined(WIN32)
1445 LARGE_INTEGER liFilePos;
1446 liFilePos.QuadPart = filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1447 SetFilePointerEx(pFile->
hFileRead, liFilePos, NULL, FILE_BEGIN);
1449 ReadFile(pFile->
hFileRead, &ListType, 4, &dwBytesRead, NULL);
1452 fread(&ListType, 4, 1, pFile->
hFileRead);
1455 std::cout <<
"listType=" << convertToString(ListType) << std::endl;
1457 if (!pFile->bEndianNative) {
1464 ullNewChunkSize += 4;
1465 Chunk::WriteHeader(filePos);
1466 ullNewChunkSize -= 4;
1470 #elif defined(WIN32)
1471 LARGE_INTEGER liFilePos;
1472 liFilePos.QuadPart = filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1473 SetFilePointerEx(pFile->
hFileWrite, liFilePos, NULL, FILE_BEGIN);
1474 DWORD dwBytesWritten;
1475 WriteFile(pFile->
hFileWrite, &ListType, 4, &dwBytesWritten, NULL);
1482 void List::LoadSubChunks(progress_t* pProgress) {
1484 std::cout <<
"List::LoadSubChunks()";
1487 pSubChunks =
new ChunkList();
1488 pSubChunksMap =
new ChunkMap();
1490 if (pFile->
hFileRead == INVALID_HANDLE_VALUE)
return;
1501 std::cout <<
" ckid=" << convertToString(ckid) << std::endl;
1503 if (ckid == CHUNK_ID_LIST) {
1504 ck =
new RIFF::List(pFile, ullStartPos + ullPos - 4,
this);
1508 ck =
new RIFF::Chunk(pFile, ullStartPos + ullPos - 4,
this);
1511 pSubChunks->push_back(ck);
1512 (*pSubChunksMap)[ckid] = ck;
1518 __notify_progress(pProgress, 1.0);
1521 void List::LoadSubChunksRecursively(progress_t* pProgress) {
1527 progress_t subprogress;
1528 __divide_progress(pProgress, &subprogress, n, i);
1530 pList->LoadSubChunksRecursively(&subprogress);
1532 pList->LoadSubChunksRecursively(NULL);
1535 __notify_progress(pProgress, 1.0);
1557 if (pFile->Mode != stream_mode_read_write)
1558 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
1563 const size_t n = pSubChunks->size();
1564 for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter, ++i) {
1568 __divide_progress(pProgress, &subprogress, n, i);
1570 ullWritePos = (*iter)->WriteChunk(ullWritePos, ullCurrentDataOffset, &subprogress);
1572 ullWritePos = (*iter)->WriteChunk(ullWritePos, ullCurrentDataOffset, NULL);
1577 ullCurrentChunkSize = ullNewChunkSize = ullWritePos - ullOriginalPos - LIST_HEADER_SIZE(pFile->
FileOffsetSize);
1578 WriteHeader(ullOriginalPos);
1581 ullStartPos = ullOriginalPos + LIST_HEADER_SIZE(pFile->
FileOffsetSize);
1584 __notify_progress(pProgress, 1.0);
1592 for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter) {
1593 (*iter)->__resetPos();
1602 return convertToString(ListType);
1633 Mode = stream_mode_closed;
1634 bEndianNative =
true;
1635 ListType = FileType;
1653 std::cout <<
"File::File("<<path<<
")" << std::endl;
1655 bEndianNative =
true;
1658 __openExistingFile(path);
1659 if (ChunkID != CHUNK_ID_RIFF && ChunkID != CHUNK_ID_RIFX) {
1696 :
List(this), Filename(path), bIsNewFile(false), Layout(layout),
1697 FileOffsetPreference(fileOffsetSize)
1701 throw Exception(
"Invalid RIFF::offset_size_t");
1704 __openExistingFile(path, &FileType);
1722 void File::__openExistingFile(
const String& path, uint32_t* FileType) {
1727 String sError = strerror(errno);
1730 #elif defined(WIN32)
1732 path.c_str(), GENERIC_READ,
1733 FILE_SHARE_READ | FILE_SHARE_WRITE,
1734 NULL, OPEN_EXISTING,
1735 FILE_ATTRIBUTE_NORMAL |
1736 FILE_FLAG_RANDOM_ACCESS, NULL
1738 if (
hFileRead == INVALID_HANDLE_VALUE) {
1746 Mode = stream_mode_read;
1756 if (FileType && ChunkID != *FileType)
1764 if (
Read(&ckid, 4, 1) != 4) {
1765 throw RIFF::Exception(
"Invalid file header ID (premature end of header)");
1766 }
else if (ckid != *FileType) {
1767 String s =
" (expected '" + convertToString(*FileType) +
"' but got '" + convertToString(ckid) +
"')";
1777 String File::GetFileName()
const {
1781 void File::SetFileName(
const String& path) {
1804 if (NewMode != Mode) {
1806 case stream_mode_read:
1812 String sError = strerror(errno);
1813 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode: " + sError);
1815 #elif defined(WIN32)
1818 Filename.c_str(), GENERIC_READ,
1819 FILE_SHARE_READ | FILE_SHARE_WRITE,
1820 NULL, OPEN_EXISTING,
1821 FILE_ATTRIBUTE_NORMAL |
1822 FILE_FLAG_RANDOM_ACCESS,
1825 if (
hFileRead == INVALID_HANDLE_VALUE) {
1827 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode");
1832 if (!
hFileRead)
throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode");
1836 case stream_mode_read_write:
1842 String sError = strerror(errno);
1843 throw Exception(
"Could not open file \"" + Filename +
"\" in read+write mode: " + sError);
1845 #elif defined(WIN32)
1849 GENERIC_READ | GENERIC_WRITE,
1852 FILE_ATTRIBUTE_NORMAL |
1853 FILE_FLAG_RANDOM_ACCESS,
1856 if (
hFileRead == INVALID_HANDLE_VALUE) {
1858 Filename.c_str(), GENERIC_READ,
1859 FILE_SHARE_READ | FILE_SHARE_WRITE,
1860 NULL, OPEN_EXISTING,
1861 FILE_ATTRIBUTE_NORMAL |
1862 FILE_FLAG_RANDOM_ACCESS,
1865 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read+write mode");
1872 throw Exception(
"Could not open file \"" + Filename +
"\" in read+write mode");
1877 case stream_mode_closed:
1882 #elif defined(WIN32)
1893 throw Exception(
"Unknown file access mode");
1912 bEndianNative = Endian != endian_little;
1914 bEndianNative = Endian != endian_big;
1930 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
1936 __divide_progress(pProgress, &subprogress, 3.f, 0.f);
1938 LoadSubChunksRecursively(&subprogress);
1940 __notify_progress(&subprogress, 1.f);
1942 LoadSubChunksRecursively(NULL);
1945 SetMode(stream_mode_read_write);
1967 if (newFileSize > workingFileSize) {
1968 positiveSizeDiff = newFileSize - workingFileSize;
1973 __divide_progress(pProgress, &subprogress, 3.f, 1.f);
1976 ResizeFile(newFileSize);
1979 int8_t* pCopyBuffer =
new int8_t[4096];
1981 DWORD iBytesMoved = 1;
1983 ssize_t iBytesMoved = 1;
1985 for (
file_offset_t ullPos = workingFileSize, iNotif = 0; iBytesMoved > 0; ++iNotif) {
1986 iBytesMoved = (ullPos < 4096) ? ullPos : 4096;
1987 ullPos -= iBytesMoved;
1990 iBytesMoved = read(
hFileRead, pCopyBuffer, iBytesMoved);
1991 lseek(
hFileWrite, ullPos + positiveSizeDiff, SEEK_SET);
1992 iBytesMoved = write(
hFileWrite, pCopyBuffer, iBytesMoved);
1993 #elif defined(WIN32)
1994 LARGE_INTEGER liFilePos;
1995 liFilePos.QuadPart = ullPos;
1996 SetFilePointerEx(
hFileRead, liFilePos, NULL, FILE_BEGIN);
1997 ReadFile(
hFileRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1998 liFilePos.QuadPart = ullPos + positiveSizeDiff;
1999 SetFilePointerEx(
hFileWrite, liFilePos, NULL, FILE_BEGIN);
2000 WriteFile(
hFileWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
2003 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved,
hFileRead);
2004 fseeko(
hFileWrite, ullPos + positiveSizeDiff, SEEK_SET);
2005 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved,
hFileWrite);
2007 if (pProgress && !(iNotif % 8) && iBytesMoved > 0)
2008 __notify_progress(&subprogress,
float(workingFileSize - ullPos) /
float(workingFileSize));
2010 delete[] pCopyBuffer;
2011 if (iBytesMoved < 0)
throw Exception(
"Could not modify file while trying to enlarge it");
2014 __notify_progress(&subprogress, 1.f);
2022 __divide_progress(pProgress, &subprogress, 3.f, 2.f);
2028 __notify_progress(&subprogress, 1.f);
2031 if (finalSize < finalActualSize) ResizeFile(finalSize);
2034 __notify_progress(pProgress, 1.0);
2056 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
2062 __divide_progress(pProgress, &subprogress, 2.f, 0.f);
2064 LoadSubChunksRecursively(&subprogress);
2066 __notify_progress(&subprogress, 1.f);
2068 LoadSubChunksRecursively(NULL);
2070 if (!bIsNewFile)
SetMode(stream_mode_read);
2073 hFileWrite = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
2076 String sError = strerror(errno);
2077 throw Exception(
"Could not open file \"" + path +
"\" for writing: " + sError);
2079 #elif defined(WIN32)
2081 path.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
2082 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL |
2083 FILE_FLAG_RANDOM_ACCESS, NULL
2087 throw Exception(
"Could not open file \"" + path +
"\" for writing");
2093 throw Exception(
"Could not open file \"" + path +
"\" for writing");
2096 Mode = stream_mode_read_write;
2110 __divide_progress(pProgress, &subprogress, 2.f, 1.f);
2112 ullTotalSize =
WriteChunk(0, 0, &subprogress);
2114 __notify_progress(&subprogress, 1.f);
2121 if (ullActualSize > ullTotalSize) ResizeFile(ullTotalSize);
2125 #elif defined(WIN32)
2136 SetMode(stream_mode_read_write);
2139 __notify_progress(pProgress, 1.0);
2145 throw Exception(
"Could not resize file \"" + Filename +
"\"");
2146 #elif defined(WIN32)
2147 LARGE_INTEGER liFilePos;
2148 liFilePos.QuadPart = ullNewSize;
2150 !SetFilePointerEx(
hFileWrite, liFilePos, NULL, FILE_BEGIN) ||
2152 )
throw Exception(
"Could not resize file \"" + Filename +
"\"");
2154 # error Sorry, this version of libgig only supports POSIX and Windows systems yet.
2155 # error Reason: portable implementation of RIFF::File::ResizeFile() is missing (yet)!
2161 std::cout <<
"File::~File()" << std::endl;
2174 void File::Cleanup() {
2177 #elif defined(WIN32)
2237 switch (fileOffsetSize) {
2247 default:
throw Exception(
"Internal error: Invalid RIFF::offset_size_t");
2253 switch (FileOffsetPreference) {
2255 return (fileSize >> 32) ? 8 : 4;
2261 throw Exception(
"Internal error: Invalid RIFF::offset_size_t");
2305 struct stat filestat;
2306 if (fstat(hFile, &filestat) == -1)
2307 throw Exception(
"POSIX FS error: could not determine file size");
2308 return filestat.st_size;
2310 #elif defined(WIN32)
2313 if (!GetFileSizeEx(hFile, &size))
2314 throw Exception(
"Windows FS error: could not determine file size");
2315 return size.QuadPart;
2319 off_t curpos = ftello(hFile);
2320 if (fseeko(hFile, 0, SEEK_END) == -1)
2321 throw Exception(
"FS error: could not determine file size");
2322 off_t size = ftello(hFile);
2323 fseeko(hFile, curpos, SEEK_SET);
2332 Exception::Exception() {
2335 Exception::Exception(String format, ...) {
2337 va_start(arg, format);
2338 Message = assemble(format, arg);
2342 Exception::Exception(String format, va_list arg) {
2343 Message = assemble(format, arg);
2346 void Exception::PrintMessage() {
2347 std::cout <<
"RIFF::Exception: " << Message << std::endl;
2350 String Exception::assemble(String format, va_list arg) {
2352 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).
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
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.
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.
int hFileRead
handle / descriptor for reading from file
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.
int hFileWrite
handle / descriptor for writing to (some) file
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 FileOffsetSize
Size of file offsets (in bytes) when this file was opened (or saved the last time).
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.
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.
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!
std::vector< progress_t > subdivide(int iSubtasks)
Divides this progress task into the requested amount of equal weighted sub-progress tasks and returns...
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.
float __range_max
Only for internal usage, do not modify!