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;
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;
199 #else // little endian
200 if (ChunkID == CHUNK_ID_RIFX) {
201 pFile->bEndianNative =
false;
202 ChunkID = CHUNK_ID_RIFF;
204 #endif // WORDS_BIGENDIAN
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;
226 #else // little endian
227 if (!pFile->bEndianNative) uiNewChunkID = CHUNK_ID_RIFX;
228 #endif // WORDS_BIGENDIAN
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;
400 #else // standard C functions
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;
488 #else // standard C functions
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);
884 ReadFile(pFile->
hFileRead, pChunkData, GetSize(), &readWords, NULL);
888 if (readWords != GetSize()) {
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;
1070 #endif // DEBUG_RIFF
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;
1079 #endif // DEBUG_RIFF
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;
1096 #endif // DEBUG_RIFF
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;
1131 #endif // DEBUG_RIFF
1132 if (!pSubChunksMap) LoadSubChunks();
1133 return (*pSubChunksMap)[ChunkID];
1149 std::cout <<
"List::GetSubList(uint32_t)" << std::endl;
1150 #endif // DEBUG_RIFF
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) {
1157 if (l->GetListType() == ListType)
return l;
1175 std::cout <<
"List::GetFirstSubChunk()" << std::endl;
1176 #endif // DEBUG_RIFF
1177 if (!pSubChunks) LoadSubChunks();
1178 ChunksIterator = pSubChunks->begin();
1179 return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1192 std::cout <<
"List::GetNextSubChunk()" << std::endl;
1193 #endif // DEBUG_RIFF
1194 if (!pSubChunks)
return NULL;
1196 return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1210 std::cout <<
"List::GetFirstSubList()" << std::endl;
1211 #endif // DEBUG_RIFF
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;
1233 #endif // DEBUG_RIFF
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) {
1289 List* l = (List*) *iter;
1290 if (l->GetListType() == ListType) result++;
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) {
1355 pSubChunksMap->erase(pSrc->GetChunkID());
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) ";
1437 #endif // DEBUG_RIFF
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;
1456 #endif // DEBUG_RIFF
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()";
1485 #endif // DEBUG_RIFF
1487 pSubChunks =
new ChunkList();
1488 pSubChunksMap =
new ChunkMap();
1490 if (pFile->
hFileRead == INVALID_HANDLE_VALUE)
return;
1501 std::cout <<
" ckid=" << convertToString(ckid) << std::endl;
1502 #endif // DEBUG_RIFF
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;
1513 if (GetPos() % 2 != 0)
SetPos(1, RIFF::stream_curpos);
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) {
1567 progress_t subprogress;
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);
1629 hFileRead = hFileWrite = INVALID_HANDLE_VALUE;
1631 hFileRead = hFileWrite = 0;
1633 Mode = stream_mode_closed;
1634 bEndianNative =
true;
1635 ListType = FileType;
1637 ullStartPos = RIFF_HEADER_SIZE(FileOffsetSize);
1649 : List(this), Filename(path), bIsNewFile(false), Layout(
layout_standard),
1653 std::cout <<
"File::File("<<path<<
")" << std::endl;
1654 #endif // DEBUG_RIFF
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)
1699 SetByteOrder(Endian);
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);
2020 progress_t subprogress;
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);
2051 void File::Save(
const String& path, progress_t* pProgress) {
2056 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
2061 progress_t subprogress;
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;
2109 progress_t subprogress;
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;
2162 #endif // DEBUG_RIFF
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;
2317 #else // standard C functions
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);