/[svn]/libgig/trunk/src/RIFF.cpp
ViewVC logotype

Diff of /libgig/trunk/src/RIFF.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 780 by schoenebeck, Sun Sep 25 13:40:37 2005 UTC revision 798 by schoenebeck, Thu Nov 3 23:49:11 2005 UTC
# Line 49  namespace RIFF { Line 49  namespace RIFF {
49          ulPos      = 0;          ulPos      = 0;
50          pParent    = NULL;          pParent    = NULL;
51          pChunkData = NULL;          pChunkData = NULL;
52            ChunkID    = CHUNK_ID_RIFF;
53          this->pFile = pFile;          this->pFile = pFile;
54      }      }
55    
# Line 293  namespace RIFF { Line 294  namespace RIFF {
294       *  @see Resize()       *  @see Resize()
295       */       */
296      unsigned long Chunk::Write(void* pData, unsigned long WordCount, unsigned long WordSize) {      unsigned long Chunk::Write(void* pData, unsigned long WordCount, unsigned long WordSize) {
297          if (pFile->Mode == stream_mode_read)          if (pFile->Mode != stream_mode_read_write)
298              throw Exception("Writing chunk data in read-only file access mode was attempted");              throw Exception("Cannot write data to chunk, file has to be opened in read+write mode first");
299          if (ulPos >= CurrentChunkSize || ulPos + WordCount * WordSize >= CurrentChunkSize)          if (ulPos >= CurrentChunkSize || ulPos + WordCount * WordSize > CurrentChunkSize)
300              throw Exception("End of chunk reached while trying to write data");              throw Exception("End of chunk reached while trying to write data");
301          if (!pFile->bEndianNative && WordSize != 1) {          if (!pFile->bEndianNative && WordSize != 1) {
302              switch (WordSize) {              switch (WordSize) {
# Line 743  namespace RIFF { Line 744  namespace RIFF {
744       *          (including its header size of course)       *          (including its header size of course)
745       */       */
746      unsigned long Chunk::WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset) {      unsigned long Chunk::WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset) {
747          unsigned long ulOriginalPos = ulWritePos;          const unsigned long ulOriginalPos = ulWritePos;
748          ulWritePos += CHUNK_HEADER_SIZE;          ulWritePos += CHUNK_HEADER_SIZE;
749    
750            if (pFile->Mode != stream_mode_read_write)
751                throw Exception("Cannot write list chunk, file has to be opened in read+write mode");
752    
753          // if the whole chunk body was loaded into RAM          // if the whole chunk body was loaded into RAM
754          if (pChunkData) {          if (pChunkData) {
755              // in case the chunk size was changed, reallocate the data in RAM with the chunk's new size              // in case the chunk size was changed, reallocate the data in RAM with the chunk's new size
# Line 806  namespace RIFF { Line 810  namespace RIFF {
810    
811          // add pad byte if needed          // add pad byte if needed
812          if ((ulStartPos + NewChunkSize) % 2 != 0) {          if ((ulStartPos + NewChunkSize) % 2 != 0) {
813              char cPadByte = 0;              const char cPadByte = 0;
814              #if POSIX              #if POSIX
815                lseek(pFile->hFileWrite, ulStartPos + NewChunkSize, SEEK_SET);
816              write(pFile->hFileWrite, &cPadByte, 1);              write(pFile->hFileWrite, &cPadByte, 1);
817              #else              #else
818                fseek(pFile->hFileWrite, ulStartPos + NewChunkSize, SEEK_SET);
819              fwrite(&cPadByte, 1, 1, pFile->hFileWrite);              fwrite(&cPadByte, 1, 1, pFile->hFileWrite);
820              #endif              #endif
821              return ulStartPos + NewChunkSize + 1;              return ulStartPos + NewChunkSize + 1;
# Line 1063  namespace RIFF { Line 1069  namespace RIFF {
1069      Chunk* List::AddSubChunk(uint32_t uiChunkID, uint uiBodySize) {      Chunk* List::AddSubChunk(uint32_t uiChunkID, uint uiBodySize) {
1070          if (uiBodySize == 0) throw Exception("Chunk body size must be at least 1 byte");          if (uiBodySize == 0) throw Exception("Chunk body size must be at least 1 byte");
1071          if (!pSubChunks) LoadSubChunks();          if (!pSubChunks) LoadSubChunks();
1072          Chunk* pNewChunk = new Chunk(pFile, this, uiChunkID, uiBodySize);          Chunk* pNewChunk = new Chunk(pFile, this, uiChunkID, 0);
1073          pSubChunks->push_back(pNewChunk);          pSubChunks->push_back(pNewChunk);
1074          (*pSubChunksMap)[uiChunkID] = pNewChunk;          (*pSubChunksMap)[uiChunkID] = pNewChunk;
1075          pFile->ResizedChunks.push_back(pNewChunk);          pNewChunk->Resize(uiBodySize);
1076          return pNewChunk;          return pNewChunk;
1077      }      }
1078    
# Line 1197  namespace RIFF { Line 1203  namespace RIFF {
1203       *          (including its header size of course)       *          (including its header size of course)
1204       */       */
1205      unsigned long List::WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset) {      unsigned long List::WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset) {
1206          unsigned long ulOriginalPos = ulWritePos;          const unsigned long ulOriginalPos = ulWritePos;
1207          ulWritePos += LIST_HEADER_SIZE;          ulWritePos += LIST_HEADER_SIZE;
1208    
1209            if (pFile->Mode != stream_mode_read_write)
1210                throw Exception("Cannot write list chunk, file has to be opened in read+write mode");
1211    
1212          // write all subchunks (including sub list chunks) recursively          // write all subchunks (including sub list chunks) recursively
1213          if (pSubChunks) {          if (pSubChunks) {
1214              for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter) {              for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter) {
# Line 1211  namespace RIFF { Line 1220  namespace RIFF {
1220          CurrentChunkSize = NewChunkSize = ulWritePos - ulOriginalPos - LIST_HEADER_SIZE;          CurrentChunkSize = NewChunkSize = ulWritePos - ulOriginalPos - LIST_HEADER_SIZE;
1221          WriteHeader(ulOriginalPos);          WriteHeader(ulOriginalPos);
1222    
1223            // offset of this list chunk in new written file may have changed
1224            ulStartPos = ulOriginalPos + LIST_HEADER_SIZE;
1225    
1226          return ulWritePos;          return ulWritePos;
1227      }      }
1228    
# Line 1241  namespace RIFF { Line 1253  namespace RIFF {
1253       * "from scratch". Note: there must be no empty chunks or empty list       * "from scratch". Note: there must be no empty chunks or empty list
1254       * chunks when trying to make the new RIFF file persistent with Save()!       * chunks when trying to make the new RIFF file persistent with Save()!
1255       *       *
1256         * @param FileType - four-byte identifier of the RIFF file type
1257       * @see AddSubChunk(), AddSubList()       * @see AddSubChunk(), AddSubList()
1258       */       */
1259      File::File() : List(this) {      File::File(uint32_t FileType) : List(this) {
1260          hFileRead = hFileWrite = 0;          hFileRead = hFileWrite = 0;
1261            Mode = stream_mode_closed;
1262          bEndianNative = true;          bEndianNative = true;
1263          ulStartPos = RIFF_HEADER_SIZE;          ulStartPos = RIFF_HEADER_SIZE;
1264            ListType = FileType;
1265      }      }
1266    
1267      /** @brief Load existing RIFF file.      /** @brief Load existing RIFF file.
# Line 1272  namespace RIFF { Line 1287  namespace RIFF {
1287          hFileRead = hFileWrite = fopen(path.c_str(), "rb");          hFileRead = hFileWrite = fopen(path.c_str(), "rb");
1288          if (!hFile) throw RIFF::Exception("Can't open \"" + path + "\"");          if (!hFile) throw RIFF::Exception("Can't open \"" + path + "\"");
1289          #endif // POSIX          #endif // POSIX
1290            Mode = stream_mode_read;
1291          ulStartPos = RIFF_HEADER_SIZE;          ulStartPos = RIFF_HEADER_SIZE;
1292          ReadHeader(0);          ReadHeader(0);
1293          if (ChunkID != CHUNK_ID_RIFF) {          if (ChunkID != CHUNK_ID_RIFF) {
# Line 1314  namespace RIFF { Line 1330  namespace RIFF {
1330                      if (!hFileRead) throw Exception("Could not (re)open file \"" + Filename + "\" in read mode");                      if (!hFileRead) throw Exception("Could not (re)open file \"" + Filename + "\" in read mode");
1331                      #endif                      #endif
1332                      __resetPos(); // reset read/write position of ALL 'Chunk' objects                      __resetPos(); // reset read/write position of ALL 'Chunk' objects
1333                      return true;                      break;
1334                  case stream_mode_read_write:                  case stream_mode_read_write:
1335                      #if POSIX                      #if POSIX
1336                      if (hFileRead) close(hFileRead);                      if (hFileRead) close(hFileRead);
# Line 1332  namespace RIFF { Line 1348  namespace RIFF {
1348                      }                      }
1349                      #endif                      #endif
1350                      __resetPos(); // reset read/write position of ALL 'Chunk' objects                      __resetPos(); // reset read/write position of ALL 'Chunk' objects
1351                      return true;                      break;
1352                    case stream_mode_closed:
1353                        #if POSIX
1354                        if (hFileRead)  close(hFileRead);
1355                        if (hFileWrite) close(hFileWrite);
1356                        #else
1357                        if (hFileRead)  fclose(hFileRead);
1358                        if (hFileWrite) fclose(hFileWrite);
1359                        #endif
1360                        hFileRead = hFileWrite = 0;
1361                        break;
1362                  default:                  default:
1363                      throw Exception("Unknown file access mode");                      throw Exception("Unknown file access mode");
1364              }              }
1365                Mode = NewMode;
1366                return true;
1367          }          }
1368          return false;          return false;
1369      }      }
# Line 1352  namespace RIFF { Line 1380  namespace RIFF {
1380       */       */
1381      void File::Save() {      void File::Save() {
1382          // reopen file in write mode          // reopen file in write mode
1383          bool bModeWasChanged = SetMode(stream_mode_read_write);          SetMode(stream_mode_read_write);
1384    
1385          // to be able to save the whole file without loading everything into          // to be able to save the whole file without loading everything into
1386          // RAM and without having to store the data in a temporary file, we          // RAM and without having to store the data in a temporary file, we
# Line 1365  namespace RIFF { Line 1393  namespace RIFF {
1393          unsigned long ulPositiveSizeDiff = 0;          unsigned long ulPositiveSizeDiff = 0;
1394          for (ChunkList::iterator iter = ResizedChunks.begin(), end = ResizedChunks.end(); iter != end; ++iter) {          for (ChunkList::iterator iter = ResizedChunks.begin(), end = ResizedChunks.end(); iter != end; ++iter) {
1395              if ((*iter)->GetNewSize() == 0) throw Exception("There is at least one empty chunk (zero size)");              if ((*iter)->GetNewSize() == 0) throw Exception("There is at least one empty chunk (zero size)");
1396              unsigned long ulDiff = (*iter)->GetNewSize() - (*iter)->GetSize() + 1L; // +1 in case we have to add a pad byte              if ((*iter)->GetNewSize() + 1L > (*iter)->GetSize()) {
1397              if (ulDiff > 0) ulPositiveSizeDiff += ulDiff;                  unsigned long ulDiff = (*iter)->GetNewSize() - (*iter)->GetSize() + 1L; // +1 in case we have to add a pad byte
1398                    ulPositiveSizeDiff += ulDiff;
1399                }
1400          }          }
1401    
1402          unsigned long ulWorkingFileSize = GetFileSize();          unsigned long ulWorkingFileSize = GetFileSize();
# Line 1400  namespace RIFF { Line 1430  namespace RIFF {
1430          }          }
1431    
1432          // rebuild / rewrite complete RIFF tree          // rebuild / rewrite complete RIFF tree
1433          unsigned long ulTotalSize = WriteChunk(0, ulPositiveSizeDiff);          unsigned long ulTotalSize  = WriteChunk(0, ulPositiveSizeDiff);
1434            unsigned long ulActualSize = __GetFileSize(hFileWrite);
1435    
1436          // resize file to the final size          // resize file to the final size
1437          if (ulTotalSize < ulWorkingFileSize) ResizeFile(ulTotalSize);          if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);
1438    
1439          // forget all resized chunks          // forget all resized chunks
1440          ResizedChunks.clear();          ResizedChunks.clear();
   
         // reopen file in read mode  
         if (bModeWasChanged) SetMode(stream_mode_read);  
1441      }      }
1442    
1443      /** @brief Save changes to another file.      /** @brief Save changes to another file.
# Line 1417  namespace RIFF { Line 1445  namespace RIFF {
1445       * Make all changes of all chunks persistent by writing them to another       * Make all changes of all chunks persistent by writing them to another
1446       * file. <b>Caution:</b> this method is optimized for writing to       * file. <b>Caution:</b> this method is optimized for writing to
1447       * <b>another</b> file, do not use it to save the changes to the same       * <b>another</b> file, do not use it to save the changes to the same
1448       * file! Use File::Save() in that case instead!       * file! Use File::Save() in that case instead! Ignoring this might
1449         * result in a corrupted file, especially in case chunks were resized!
1450       *       *
1451       * After calling this method, this File object will be associated with       * After calling this method, this File object will be associated with
1452       * the new file (given by \a path) afterwards.       * the new file (given by \a path) afterwards.
# Line 1425  namespace RIFF { Line 1454  namespace RIFF {
1454       * @param path - path and file name where everything should be written to       * @param path - path and file name where everything should be written to
1455       */       */
1456      void File::Save(const String& path) {      void File::Save(const String& path) {
1457            //TODO: we should make a check here if somebody tries to write to the same file and automatically call the other Save() method in that case
1458    
1459            if (Filename.length() > 0) SetMode(stream_mode_read);
1460          // open the other (new) file for writing and truncate it to zero size          // open the other (new) file for writing and truncate it to zero size
1461          #if POSIX          #if POSIX
1462          hFileWrite = open(path.c_str(), O_RDWR | O_CREAT | O_TRUNC);          hFileWrite = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
1463          if (hFileWrite < 0) {          if (hFileWrite < 0) {
1464              hFileWrite = hFileRead;              hFileWrite = hFileRead;
1465              throw Exception("Could not open file \"" + path + "\" for writing");              throw Exception("Could not open file \"" + path + "\" for writing");
# Line 1439  namespace RIFF { Line 1471  namespace RIFF {
1471              throw Exception("Could not open file \"" + path + "\" for writing");              throw Exception("Could not open file \"" + path + "\" for writing");
1472          }          }
1473          #endif // POSIX          #endif // POSIX
1474            Mode = stream_mode_read_write;
1475    
1476          // write complete RIFF tree to the other (new) file          // write complete RIFF tree to the other (new) file
1477          WriteChunk(0, 0);          unsigned long ulTotalSize  = WriteChunk(0, 0);
1478            unsigned long ulActualSize = __GetFileSize(hFileWrite);
1479    
1480            // resize file to the final size (if the file was originally larger)
1481            if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);
1482    
1483          // forget all resized chunks          // forget all resized chunks
1484          ResizedChunks.clear();          ResizedChunks.clear();
1485    
1486            if (Filename.length() > 0) {
1487                #if POSIX
1488                close(hFileWrite);
1489                #else
1490                fclose(hFileWrite);
1491                #endif
1492                hFileWrite = hFileRead;
1493            }
1494    
1495          // associate new file with this File object from now on          // associate new file with this File object from now on
1496          Filename = path;          Filename = path;
1497          stream_mode_t oldMode = Mode;          Mode = (stream_mode_t) -1;       // Just set it to an undefined mode ...
1498          Mode = (stream_mode_t) -1; // Just set it to an undefined mode ...          SetMode(stream_mode_read_write); // ... so SetMode() has to reopen the file handles.
         SetMode(oldMode);          // ... so SetMode() has to reopen the file handles.  
1499      }      }
1500    
1501      void File::ResizeFile(unsigned long ulNewSize) {      void File::ResizeFile(unsigned long ulNewSize) {
# Line 1459  namespace RIFF { Line 1504  namespace RIFF {
1504              throw Exception("Could not resize file \"" + Filename + "\"");              throw Exception("Could not resize file \"" + Filename + "\"");
1505          #else          #else
1506          # error Sorry, this version of libgig only supports POSIX systems yet.          # error Sorry, this version of libgig only supports POSIX systems yet.
1507          # error Reason: portable implementation of RIFF::File::ResizeFile() is missing!          # error Reason: portable implementation of RIFF::File::ResizeFile() is missing (yet)!
1508          #endif          #endif
1509      }      }
1510    
# Line 1479  namespace RIFF { Line 1524  namespace RIFF {
1524      }      }
1525    
1526      unsigned long File::GetFileSize() {      unsigned long File::GetFileSize() {
1527          #if POSIX          return __GetFileSize(hFileRead);
1528        }
1529    
1530        #if POSIX
1531        unsigned long File::__GetFileSize(int hFile) {
1532          struct stat filestat;          struct stat filestat;
1533          fstat(hFileRead, &filestat);          fstat(hFile, &filestat);
1534          long size = filestat.st_size;          long size = filestat.st_size;
         #else // standard C functions  
         long curpos = ftell(hFileRead);  
         fseek(hFileRead, 0, SEEK_END);  
         long size = ftell(hFileRead);  
         fseek(hFileRead, curpos, SEEK_SET);  
         #endif // POSIX  
1535          return size;          return size;
1536      }      }
1537        #else // standard C functions
1538        unsigned long File::__GetFileSize(FILE* hFile) {
1539            long curpos = ftell(hFile);
1540            fseek(hFile, 0, SEEK_END);
1541            long size = ftell(hFile);
1542            fseek(hFile, curpos, SEEK_SET);
1543            return size;
1544        }
1545        #endif
1546    
1547    
1548  // *************** Exception ***************  // *************** Exception ***************

Legend:
Removed from v.780  
changed lines
  Added in v.798

  ViewVC Help
Powered by ViewVC