--- libgig/trunk/src/RIFF.cpp 2007/05/13 10:34:29 1183 +++ libgig/trunk/src/RIFF.cpp 2008/03/06 20:42:22 1713 @@ -21,6 +21,7 @@ * MA 02111-1307 USA * ***************************************************************************/ +#include #include #include "RIFF.h" @@ -33,7 +34,7 @@ // * /// Returns a human readable path of the given chunk. - String __resolveChunkPath(Chunk* pCk) { + static String __resolveChunkPath(Chunk* pCk) { String sPath; for (Chunk* pChunk = pCk; pChunk; pChunk = pChunk->GetParent()) { if (pChunk->GetChunkID() == CHUNK_ID_LIST) { @@ -89,7 +90,7 @@ } Chunk::~Chunk() { - if (CurrentChunkSize != NewChunkSize) pFile->UnlogResized(this); + pFile->UnlogResized(this); if (pChunkData) delete[] pChunkData; } @@ -235,7 +236,7 @@ * - RIFF::stream_closed : * the data stream was closed somehow, no more reading possible * - RIFF::stream_end_reached : - * alreaady reached the end of the chunk data, no more reading + * already reached the end of the chunk data, no more reading * possible without SetPos() */ stream_state_t Chunk::GetState() { @@ -358,7 +359,7 @@ #elif defined(WIN32) if (SetFilePointer(pFile->hFileWrite, ulStartPos + ulPos, NULL/*32 bit*/, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { throw Exception("Could not seek to position " + ToString(ulPos) + - " in chunk (" + ToString(ulStartPos + ulPos) + " in file)"); + " in chunk (" + ToString(ulStartPos + ulPos) + " in file)"); } DWORD writtenWords; WriteFile(pFile->hFileWrite, pData, WordCount * WordSize, &writtenWords, NULL); @@ -1152,6 +1153,8 @@ pSubChunks->push_back(pNewChunk); (*pSubChunksMap)[uiChunkID] = pNewChunk; pNewChunk->Resize(uiBodySize); + NewChunkSize += CHUNK_HEADER_SIZE; + pFile->LogAsResized(this); return pNewChunk; } @@ -1187,6 +1190,8 @@ List* pNewListChunk = new List(pFile, this, uiListType); pSubChunks->push_back(pNewListChunk); (*pSubChunksMap)[CHUNK_ID_LIST] = pNewListChunk; + NewChunkSize += LIST_HEADER_SIZE; + pFile->LogAsResized(this); return pNewListChunk; } @@ -1268,7 +1273,11 @@ if (!pSubChunks) { pSubChunks = new ChunkList(); pSubChunksMap = new ChunkMap(); + #if defined(WIN32) + if (pFile->hFileRead == INVALID_HANDLE_VALUE) return; + #else if (!pFile->hFileRead) return; + #endif unsigned long uiOriginalPos = GetPos(); SetPos(0); // jump to beginning of list chunk body while (RemainingBytes() >= CHUNK_HEADER_SIZE) { @@ -1363,11 +1372,14 @@ * Use this constructor if you want to create a new RIFF file completely * "from scratch". Note: there must be no empty chunks or empty list * chunks when trying to make the new RIFF file persistent with Save()! - * Note that this constructor will create a RIFX file on - * big-endian machines. + * + * Note: by default, the RIFF file will be saved in native endian + * format; that is, as a RIFF file on little-endian machines and + * as a RIFX file on big-endian. To change this behaviour, call + * SetByteOrder() before calling Save(). * * @param FileType - four-byte identifier of the RIFF file type - * @see AddSubChunk(), AddSubList() + * @see AddSubChunk(), AddSubList(), SetByteOrder() */ File::File(uint32_t FileType) : List(this) { #if defined(WIN32) @@ -1381,39 +1393,6 @@ ListType = FileType; } - - /** @brief Create new RIFF file. - * - * Use this constructor if you want to create a new RIFF file - * completely "from scratch" and also want to specify - * endianess. Note: there must be no empty chunks or empty list - * chunks when trying to make the new RIFF file persistent with - * Save()! - * - * @param FileType - four-byte identifier of the RIFF file type - * @param Endian - endianess used in the new file. A value of - * endian_little will create a RIFF file, - * endian_big a RIFX file, endian_native will - * create a RIFF file on little-endian machines - * and RIFX on big-endian. - * @see AddSubChunk(), AddSubList() - */ - File::File(uint32_t FileType, endian_t Endian) : List(this) { - #if defined(WIN32) - hFileRead = hFileWrite = INVALID_HANDLE_VALUE; - #else - hFileRead = hFileWrite = 0; - #endif - Mode = stream_mode_closed; - #if WORDS_BIGENDIAN - bEndianNative = Endian != endian_little; - #else - bEndianNative = Endian != endian_big; - #endif - ulStartPos = RIFF_HEADER_SIZE; - ListType = FileType; - } - /** @brief Load existing RIFF file. * * Loads an existing RIFF file with all its chunks. @@ -1438,7 +1417,8 @@ path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL + FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_RANDOM_ACCESS, NULL ); if (hFileRead == INVALID_HANDLE_VALUE) { hFileRead = hFileWrite = INVALID_HANDLE_VALUE; @@ -1491,7 +1471,9 @@ Filename.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL + FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_RANDOM_ACCESS, + NULL ); if (hFileRead == INVALID_HANDLE_VALUE) { hFileRead = hFileWrite = INVALID_HANDLE_VALUE; @@ -1519,16 +1501,20 @@ GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL + FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_RANDOM_ACCESS, + NULL ); if (hFileRead == INVALID_HANDLE_VALUE) { hFileRead = hFileWrite = CreateFile( Filename.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL + FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_RANDOM_ACCESS, + NULL ); - throw Exception("Could not (re)open file \"" + Filename + "\" in read mode"); + throw Exception("Could not (re)open file \"" + Filename + "\" in read+write mode"); } #else if (hFileRead) fclose(hFileRead); @@ -1562,6 +1548,23 @@ return false; } + /** @brief Set the byte order to be used when saving. + * + * Set the byte order to be used in the file. A value of + * endian_little will create a RIFF file, endian_big a RIFX file + * and endian_native will create a RIFF file on little-endian + * machines and RIFX on big-endian machines. + * + * @param Endian - endianess to use when file is saved. + */ + void File::SetByteOrder(endian_t Endian) { + #if WORDS_BIGENDIAN + bEndianNative = Endian != endian_little; + #else + bEndianNative = Endian != endian_big; + #endif + } + /** @brief Save changes to same file. * * Make all changes of all chunks persistent by writing them to the @@ -1588,14 +1591,12 @@ // first we sum up all positive chunk size changes (and skip all negative ones) unsigned long ulPositiveSizeDiff = 0; - for (ChunkList::iterator iter = ResizedChunks.begin(), end = ResizedChunks.end(); iter != end; ++iter) { + for (std::set::const_iterator iter = ResizedChunks.begin(), end = ResizedChunks.end(); iter != end; ++iter) { if ((*iter)->GetNewSize() == 0) { throw Exception("There is at least one empty chunk (zero size): " + __resolveChunkPath(*iter)); } - if ((*iter)->GetNewSize() + 1L > (*iter)->GetSize()) { - unsigned long ulDiff = (*iter)->GetNewSize() - (*iter)->GetSize() + 1L; // +1 in case we have to add a pad byte - ulPositiveSizeDiff += ulDiff; - } + unsigned long ulDiff = (*iter)->GetNewSize() + (*iter)->GetNewSize() % 2 - (*iter)->GetSize() - (*iter)->GetSize() % 2; + if (ulDiff > 0) ulPositiveSizeDiff += ulDiff; } unsigned long ulWorkingFileSize = GetFileSize(); @@ -1611,11 +1612,11 @@ #if defined(WIN32) DWORD iBytesMoved = 1; // we have to pass it via pointer to the Windows API, thus the correct size must be ensured #else - int iBytesMoved = 1; + int iBytesMoved = 1; #endif - for (unsigned long ulPos = 0; iBytesMoved > 0; ulPos += iBytesMoved) { - const unsigned long ulToMove = ulFileSize - ulPos; - iBytesMoved = (ulToMove < 4096) ? ulToMove : 4096; + for (unsigned long ulPos = ulFileSize; iBytesMoved > 0; ) { + iBytesMoved = (ulPos < 4096) ? ulPos : 4096; + ulPos -= iBytesMoved; #if POSIX lseek(hFileRead, ulPos, SEEK_SET); iBytesMoved = read(hFileRead, pCopyBuffer, iBytesMoved); @@ -1678,7 +1679,8 @@ #elif defined(WIN32) hFileWrite = CreateFile( path.c_str(), GENERIC_WRITE, FILE_SHARE_READ, - NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL + NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_RANDOM_ACCESS, NULL ); if (hFileWrite == INVALID_HANDLE_VALUE) { hFileWrite = hFileRead; @@ -1703,16 +1705,14 @@ // forget all resized chunks ResizedChunks.clear(); - if (Filename.length() > 0) { - #if POSIX - close(hFileWrite); - #elif defined(WIN32) - CloseHandle(hFileWrite); - #else - fclose(hFileWrite); - #endif - hFileWrite = hFileRead; - } + #if POSIX + if (hFileWrite) close(hFileWrite); + #elif defined(WIN32) + if (hFileWrite != INVALID_HANDLE_VALUE) CloseHandle(hFileWrite); + #else + if (hFileWrite) fclose(hFileWrite); + #endif + hFileWrite = hFileRead; // associate new file with this File object from now on Filename = path; @@ -1749,11 +1749,11 @@ } void File::LogAsResized(Chunk* pResizedChunk) { - ResizedChunks.push_back(pResizedChunk); + ResizedChunks.insert(pResizedChunk); } void File::UnlogResized(Chunk* pResizedChunk) { - ResizedChunks.remove(pResizedChunk); + ResizedChunks.erase(pResizedChunk); } unsigned long File::GetFileSize() {