libgig  4.0.0
RIFF.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * *
3  * libgig - C++ cross-platform Gigasampler format file access library *
4  * *
5  * Copyright (C) 2003-2015 by Christian Schoenebeck *
6  * <cuse@users.sourceforge.net> *
7  * *
8  * This library is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This library is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this library; if not, write to the Free Software *
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21  * MA 02111-1307 USA *
22  ***************************************************************************/
23 
24 #include <algorithm>
25 #include <set>
26 #include <string.h>
27 
28 #include "RIFF.h"
29 
30 #include "helper.h"
31 
32 #if POSIX
33 # include <errno.h>
34 #endif
35 
36 namespace RIFF {
37 
38 // *************** Internal functions **************
39 // *
40 
42  static String __resolveChunkPath(Chunk* pCk) {
43  String sPath;
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;
48  } else {
49  sPath = "->'" + pChunk->GetChunkIDString() + "'" + sPath;
50  }
51  }
52  return sPath;
53  }
54 
55 
56 
57 // *************** progress_t ***************
58 // *
59 
61  callback = NULL;
62  custom = NULL;
63  __range_min = 0.0f;
64  __range_max = 1.0f;
65  }
66 
67 
68 
69 // *************** Chunk **************
70 // *
71 
72  Chunk::Chunk(File* pFile) {
73  #if DEBUG
74  std::cout << "Chunk::Chunk(File* pFile)" << std::endl;
75  #endif // DEBUG
76  ulPos = 0;
77  pParent = NULL;
78  pChunkData = NULL;
79  CurrentChunkSize = 0;
80  NewChunkSize = 0;
81  ulChunkDataSize = 0;
82  ChunkID = CHUNK_ID_RIFF;
83  this->pFile = pFile;
84  }
85 
86  Chunk::Chunk(File* pFile, unsigned long StartPos, List* Parent) {
87  #if DEBUG
88  std::cout << "Chunk::Chunk(File*,ulong,bool,List*),StartPos=" << StartPos << std::endl;
89  #endif // DEBUG
90  this->pFile = pFile;
91  ulStartPos = StartPos + CHUNK_HEADER_SIZE;
92  pParent = Parent;
93  ulPos = 0;
94  pChunkData = NULL;
95  CurrentChunkSize = 0;
96  NewChunkSize = 0;
97  ulChunkDataSize = 0;
98  ReadHeader(StartPos);
99  }
100 
101  Chunk::Chunk(File* pFile, List* pParent, uint32_t uiChunkID, uint uiBodySize) {
102  this->pFile = pFile;
103  ulStartPos = 0; // arbitrary usually, since it will be updated when we write the chunk
104  this->pParent = pParent;
105  ulPos = 0;
106  pChunkData = NULL;
107  ChunkID = uiChunkID;
108  ulChunkDataSize = 0;
109  CurrentChunkSize = 0;
110  NewChunkSize = uiBodySize;
111  }
112 
114  if (pFile) pFile->UnlogResized(this);
115  if (pChunkData) delete[] pChunkData;
116  }
117 
118  void Chunk::ReadHeader(unsigned long fPos) {
119  #if DEBUG
120  std::cout << "Chunk::Readheader(" << fPos << ") ";
121  #endif // DEBUG
122  ChunkID = 0;
123  NewChunkSize = CurrentChunkSize = 0;
124  #if POSIX
125  if (lseek(pFile->hFileRead, fPos, SEEK_SET) != -1) {
126  read(pFile->hFileRead, &ChunkID, 4);
127  read(pFile->hFileRead, &CurrentChunkSize, 4);
128  #elif defined(WIN32)
129  if (SetFilePointer(pFile->hFileRead, fPos, NULL/*32 bit*/, FILE_BEGIN) != INVALID_SET_FILE_POINTER) {
130  DWORD dwBytesRead;
131  ReadFile(pFile->hFileRead, &ChunkID, 4, &dwBytesRead, NULL);
132  ReadFile(pFile->hFileRead, &CurrentChunkSize, 4, &dwBytesRead, NULL);
133  #else
134  if (!fseek(pFile->hFileRead, fPos, SEEK_SET)) {
135  fread(&ChunkID, 4, 1, pFile->hFileRead);
136  fread(&CurrentChunkSize, 4, 1, pFile->hFileRead);
137  #endif // POSIX
138  #if WORDS_BIGENDIAN
139  if (ChunkID == CHUNK_ID_RIFF) {
140  pFile->bEndianNative = false;
141  }
142  #else // little endian
143  if (ChunkID == CHUNK_ID_RIFX) {
144  pFile->bEndianNative = false;
145  ChunkID = CHUNK_ID_RIFF;
146  }
147  #endif // WORDS_BIGENDIAN
148  if (!pFile->bEndianNative) {
149  //swapBytes_32(&ChunkID);
150  swapBytes_32(&CurrentChunkSize);
151  }
152  #if DEBUG
153  std::cout << "ckID=" << convertToString(ChunkID) << " ";
154  std::cout << "ckSize=" << CurrentChunkSize << " ";
155  std::cout << "bEndianNative=" << pFile->bEndianNative << std::endl;
156  #endif // DEBUG
157  NewChunkSize = CurrentChunkSize;
158  }
159  }
160 
161  void Chunk::WriteHeader(unsigned long fPos) {
162  uint32_t uiNewChunkID = ChunkID;
163  if (ChunkID == CHUNK_ID_RIFF) {
164  #if WORDS_BIGENDIAN
165  if (pFile->bEndianNative) uiNewChunkID = CHUNK_ID_RIFX;
166  #else // little endian
167  if (!pFile->bEndianNative) uiNewChunkID = CHUNK_ID_RIFX;
168  #endif // WORDS_BIGENDIAN
169  }
170 
171  uint32_t uiNewChunkSize = NewChunkSize;
172  if (!pFile->bEndianNative) {
173  swapBytes_32(&uiNewChunkSize);
174  }
175 
176  #if POSIX
177  if (lseek(pFile->hFileWrite, fPos, SEEK_SET) != -1) {
178  write(pFile->hFileWrite, &uiNewChunkID, 4);
179  write(pFile->hFileWrite, &uiNewChunkSize, 4);
180  }
181  #elif defined(WIN32)
182  if (SetFilePointer(pFile->hFileWrite, fPos, NULL/*32 bit*/, FILE_BEGIN) != INVALID_SET_FILE_POINTER) {
183  DWORD dwBytesWritten;
184  WriteFile(pFile->hFileWrite, &uiNewChunkID, 4, &dwBytesWritten, NULL);
185  WriteFile(pFile->hFileWrite, &uiNewChunkSize, 4, &dwBytesWritten, NULL);
186  }
187  #else
188  if (!fseek(pFile->hFileWrite, fPos, SEEK_SET)) {
189  fwrite(&uiNewChunkID, 4, 1, pFile->hFileWrite);
190  fwrite(&uiNewChunkSize, 4, 1, pFile->hFileWrite);
191  }
192  #endif // POSIX
193  }
194 
200  return convertToString(ChunkID);
201  }
202 
215  unsigned long Chunk::SetPos(unsigned long Where, stream_whence_t Whence) {
216  #if DEBUG
217  std::cout << "Chunk::SetPos(ulong)" << std::endl;
218  #endif // DEBUG
219  switch (Whence) {
220  case stream_curpos:
221  ulPos += Where;
222  break;
223  case stream_end:
224  ulPos = CurrentChunkSize - 1 - Where;
225  break;
226  case stream_backward:
227  ulPos -= Where;
228  break;
229  case stream_start: default:
230  ulPos = Where;
231  break;
232  }
233  if (ulPos > CurrentChunkSize) ulPos = CurrentChunkSize;
234  return ulPos;
235  }
236 
247  unsigned long Chunk::RemainingBytes() {
248  #if DEBUG
249  std::cout << "Chunk::Remainingbytes()=" << CurrentChunkSize - ulPos << std::endl;
250  #endif // DEBUG
251  return (CurrentChunkSize > ulPos) ? CurrentChunkSize - ulPos : 0;
252  }
253 
266  #if DEBUG
267  std::cout << "Chunk::GetState()" << std::endl;
268  #endif // DEBUG
269  #if POSIX
270  if (pFile->hFileRead == 0) return stream_closed;
271  #elif defined (WIN32)
272  if (pFile->hFileRead == INVALID_HANDLE_VALUE)
273  return stream_closed;
274  #else
275  if (pFile->hFileRead == NULL) return stream_closed;
276  #endif // POSIX
277  if (ulPos < CurrentChunkSize) return stream_ready;
278  else return stream_end_reached;
279  }
280 
296  unsigned long Chunk::Read(void* pData, unsigned long WordCount, unsigned long WordSize) {
297  #if DEBUG
298  std::cout << "Chunk::Read(void*,ulong,ulong)" << std::endl;
299  #endif // DEBUG
300  //if (ulStartPos == 0) return 0; // is only 0 if this is a new chunk, so nothing to read (yet)
301  if (ulPos >= CurrentChunkSize) return 0;
302  if (ulPos + WordCount * WordSize >= CurrentChunkSize) WordCount = (CurrentChunkSize - ulPos) / WordSize;
303  #if POSIX
304  if (lseek(pFile->hFileRead, ulStartPos + ulPos, SEEK_SET) < 0) return 0;
305  ssize_t readWords = read(pFile->hFileRead, pData, WordCount * WordSize);
306  if (readWords < 1) {
307  #if DEBUG
308  std::cerr << "POSIX read() failed: " << strerror(errno) << std::endl << std::flush;
309  #endif // DEBUG
310  return 0;
311  }
312  readWords /= WordSize;
313  #elif defined(WIN32)
314  if (SetFilePointer(pFile->hFileRead, ulStartPos + ulPos, NULL/*32 bit*/, FILE_BEGIN) == INVALID_SET_FILE_POINTER) return 0;
315  DWORD readWords;
316  ReadFile(pFile->hFileRead, pData, WordCount * WordSize, &readWords, NULL);
317  if (readWords < 1) return 0;
318  readWords /= WordSize;
319  #else // standard C functions
320  if (fseek(pFile->hFileRead, ulStartPos + ulPos, SEEK_SET)) return 0;
321  size_t readWords = fread(pData, WordSize, WordCount, pFile->hFileRead);
322  #endif // POSIX
323  if (!pFile->bEndianNative && WordSize != 1) {
324  switch (WordSize) {
325  case 2:
326  for (unsigned long iWord = 0; iWord < readWords; iWord++)
327  swapBytes_16((uint16_t*) pData + iWord);
328  break;
329  case 4:
330  for (unsigned long iWord = 0; iWord < readWords; iWord++)
331  swapBytes_32((uint32_t*) pData + iWord);
332  break;
333  default:
334  for (unsigned long iWord = 0; iWord < readWords; iWord++)
335  swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
336  break;
337  }
338  }
339  SetPos(readWords * WordSize, stream_curpos);
340  return readWords;
341  }
342 
359  unsigned long Chunk::Write(void* pData, unsigned long WordCount, unsigned long WordSize) {
360  if (pFile->Mode != stream_mode_read_write)
361  throw Exception("Cannot write data to chunk, file has to be opened in read+write mode first");
362  if (ulPos >= CurrentChunkSize || ulPos + WordCount * WordSize > CurrentChunkSize)
363  throw Exception("End of chunk reached while trying to write data");
364  if (!pFile->bEndianNative && WordSize != 1) {
365  switch (WordSize) {
366  case 2:
367  for (unsigned long iWord = 0; iWord < WordCount; iWord++)
368  swapBytes_16((uint16_t*) pData + iWord);
369  break;
370  case 4:
371  for (unsigned long iWord = 0; iWord < WordCount; iWord++)
372  swapBytes_32((uint32_t*) pData + iWord);
373  break;
374  default:
375  for (unsigned long iWord = 0; iWord < WordCount; iWord++)
376  swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
377  break;
378  }
379  }
380  #if POSIX
381  if (lseek(pFile->hFileWrite, ulStartPos + ulPos, SEEK_SET) < 0) {
382  throw Exception("Could not seek to position " + ToString(ulPos) +
383  " in chunk (" + ToString(ulStartPos + ulPos) + " in file)");
384  }
385  unsigned long writtenWords = write(pFile->hFileWrite, pData, WordCount * WordSize);
386  if (writtenWords < 1) throw Exception("POSIX IO Error while trying to write chunk data");
387  writtenWords /= WordSize;
388  #elif defined(WIN32)
389  if (SetFilePointer(pFile->hFileWrite, ulStartPos + ulPos, NULL/*32 bit*/, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
390  throw Exception("Could not seek to position " + ToString(ulPos) +
391  " in chunk (" + ToString(ulStartPos + ulPos) + " in file)");
392  }
393  DWORD writtenWords;
394  WriteFile(pFile->hFileWrite, pData, WordCount * WordSize, &writtenWords, NULL);
395  if (writtenWords < 1) throw Exception("Windows IO Error while trying to write chunk data");
396  writtenWords /= WordSize;
397  #else // standard C functions
398  if (fseek(pFile->hFileWrite, ulStartPos + ulPos, SEEK_SET)) {
399  throw Exception("Could not seek to position " + ToString(ulPos) +
400  " in chunk (" + ToString(ulStartPos + ulPos) + " in file)");
401  }
402  unsigned long writtenWords = fwrite(pData, WordSize, WordCount, pFile->hFileWrite);
403  #endif // POSIX
404  SetPos(writtenWords * WordSize, stream_curpos);
405  return writtenWords;
406  }
407 
409  unsigned long Chunk::ReadSceptical(void* pData, unsigned long WordCount, unsigned long WordSize) {
410  unsigned long readWords = Read(pData, WordCount, WordSize);
411  if (readWords != WordCount) throw RIFF::Exception("End of chunk data reached.");
412  return readWords;
413  }
414 
426  unsigned long Chunk::ReadInt8(int8_t* pData, unsigned long WordCount) {
427  #if DEBUG
428  std::cout << "Chunk::ReadInt8(int8_t*,ulong)" << std::endl;
429  #endif // DEBUG
430  return ReadSceptical(pData, WordCount, 1);
431  }
432 
447  unsigned long Chunk::WriteInt8(int8_t* pData, unsigned long WordCount) {
448  return Write(pData, WordCount, 1);
449  }
450 
463  unsigned long Chunk::ReadUint8(uint8_t* pData, unsigned long WordCount) {
464  #if DEBUG
465  std::cout << "Chunk::ReadUint8(uint8_t*,ulong)" << std::endl;
466  #endif // DEBUG
467  return ReadSceptical(pData, WordCount, 1);
468  }
469 
484  unsigned long Chunk::WriteUint8(uint8_t* pData, unsigned long WordCount) {
485  return Write(pData, WordCount, 1);
486  }
487 
500  unsigned long Chunk::ReadInt16(int16_t* pData, unsigned long WordCount) {
501  #if DEBUG
502  std::cout << "Chunk::ReadInt16(int16_t*,ulong)" << std::endl;
503  #endif // DEBUG
504  return ReadSceptical(pData, WordCount, 2);
505  }
506 
521  unsigned long Chunk::WriteInt16(int16_t* pData, unsigned long WordCount) {
522  return Write(pData, WordCount, 2);
523  }
524 
537  unsigned long Chunk::ReadUint16(uint16_t* pData, unsigned long WordCount) {
538  #if DEBUG
539  std::cout << "Chunk::ReadUint16(uint16_t*,ulong)" << std::endl;
540  #endif // DEBUG
541  return ReadSceptical(pData, WordCount, 2);
542  }
543 
558  unsigned long Chunk::WriteUint16(uint16_t* pData, unsigned long WordCount) {
559  return Write(pData, WordCount, 2);
560  }
561 
574  unsigned long Chunk::ReadInt32(int32_t* pData, unsigned long WordCount) {
575  #if DEBUG
576  std::cout << "Chunk::ReadInt32(int32_t*,ulong)" << std::endl;
577  #endif // DEBUG
578  return ReadSceptical(pData, WordCount, 4);
579  }
580 
595  unsigned long Chunk::WriteInt32(int32_t* pData, unsigned long WordCount) {
596  return Write(pData, WordCount, 4);
597  }
598 
611  unsigned long Chunk::ReadUint32(uint32_t* pData, unsigned long WordCount) {
612  #if DEBUG
613  std::cout << "Chunk::ReadUint32(uint32_t*,ulong)" << std::endl;
614  #endif // DEBUG
615  return ReadSceptical(pData, WordCount, 4);
616  }
617 
628  void Chunk::ReadString(String& s, int size) {
629  char* buf = new char[size];
630  ReadSceptical(buf, 1, size);
631  s.assign(buf, std::find(buf, buf + size, '\0'));
632  delete[] buf;
633  }
634 
649  unsigned long Chunk::WriteUint32(uint32_t* pData, unsigned long WordCount) {
650  return Write(pData, WordCount, 4);
651  }
652 
660  int8_t Chunk::ReadInt8() {
661  #if DEBUG
662  std::cout << "Chunk::ReadInt8()" << std::endl;
663  #endif // DEBUG
664  int8_t word;
665  ReadSceptical(&word,1,1);
666  return word;
667  }
668 
676  uint8_t Chunk::ReadUint8() {
677  #if DEBUG
678  std::cout << "Chunk::ReadUint8()" << std::endl;
679  #endif // DEBUG
680  uint8_t word;
681  ReadSceptical(&word,1,1);
682  return word;
683  }
684 
693  int16_t Chunk::ReadInt16() {
694  #if DEBUG
695  std::cout << "Chunk::ReadInt16()" << std::endl;
696  #endif // DEBUG
697  int16_t word;
698  ReadSceptical(&word,1,2);
699  return word;
700  }
701 
710  uint16_t Chunk::ReadUint16() {
711  #if DEBUG
712  std::cout << "Chunk::ReadUint16()" << std::endl;
713  #endif // DEBUG
714  uint16_t word;
715  ReadSceptical(&word,1,2);
716  return word;
717  }
718 
727  int32_t Chunk::ReadInt32() {
728  #if DEBUG
729  std::cout << "Chunk::ReadInt32()" << std::endl;
730  #endif // DEBUG
731  int32_t word;
732  ReadSceptical(&word,1,4);
733  return word;
734  }
735 
744  uint32_t Chunk::ReadUint32() {
745  #if DEBUG
746  std::cout << "Chunk::ReadUint32()" << std::endl;
747  #endif // DEBUG
748  uint32_t word;
749  ReadSceptical(&word,1,4);
750  return word;
751  }
752 
775  if (!pChunkData && pFile->Filename != "" /*&& ulStartPos != 0*/) {
776  #if POSIX
777  if (lseek(pFile->hFileRead, ulStartPos, SEEK_SET) == -1) return NULL;
778  #elif defined(WIN32)
779  if (SetFilePointer(pFile->hFileRead, ulStartPos, NULL/*32 bit*/, FILE_BEGIN) == INVALID_SET_FILE_POINTER) return NULL;
780  #else
781  if (fseek(pFile->hFileRead, ulStartPos, SEEK_SET)) return NULL;
782  #endif // POSIX
783  unsigned long ulBufferSize = (CurrentChunkSize > NewChunkSize) ? CurrentChunkSize : NewChunkSize;
784  pChunkData = new uint8_t[ulBufferSize];
785  if (!pChunkData) return NULL;
786  memset(pChunkData, 0, ulBufferSize);
787  #if POSIX
788  unsigned long readWords = read(pFile->hFileRead, pChunkData, GetSize());
789  #elif defined(WIN32)
790  DWORD readWords;
791  ReadFile(pFile->hFileRead, pChunkData, GetSize(), &readWords, NULL);
792  #else
793  unsigned long readWords = fread(pChunkData, 1, GetSize(), pFile->hFileRead);
794  #endif // POSIX
795  if (readWords != GetSize()) {
796  delete[] pChunkData;
797  return (pChunkData = NULL);
798  }
799  ulChunkDataSize = ulBufferSize;
800  } else if (NewChunkSize > ulChunkDataSize) {
801  uint8_t* pNewBuffer = new uint8_t[NewChunkSize];
802  if (!pNewBuffer) throw Exception("Could not enlarge chunk data buffer to " + ToString(NewChunkSize) + " bytes");
803  memset(pNewBuffer, 0 , NewChunkSize);
804  memcpy(pNewBuffer, pChunkData, ulChunkDataSize);
805  delete[] pChunkData;
806  pChunkData = pNewBuffer;
807  ulChunkDataSize = NewChunkSize;
808  }
809  return pChunkData;
810  }
811 
819  if (pChunkData) {
820  delete[] pChunkData;
821  pChunkData = NULL;
822  }
823  }
824 
843  void Chunk::Resize(int iNewSize) {
844  if (iNewSize <= 0)
845  throw Exception("There is at least one empty chunk (zero size): " + __resolveChunkPath(this));
846  if (NewChunkSize == iNewSize) return;
847  NewChunkSize = iNewSize;
848  pFile->LogAsResized(this);
849  }
850 
864  unsigned long Chunk::WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset, progress_t* pProgress) {
865  const unsigned long ulOriginalPos = ulWritePos;
866  ulWritePos += CHUNK_HEADER_SIZE;
867 
868  if (pFile->Mode != stream_mode_read_write)
869  throw Exception("Cannot write list chunk, file has to be opened in read+write mode");
870 
871  // if the whole chunk body was loaded into RAM
872  if (pChunkData) {
873  // make sure chunk data buffer in RAM is at least as large as the new chunk size
874  LoadChunkData();
875  // write chunk data from RAM persistently to the file
876  #if POSIX
877  lseek(pFile->hFileWrite, ulWritePos, SEEK_SET);
878  if (write(pFile->hFileWrite, pChunkData, NewChunkSize) != NewChunkSize) {
879  throw Exception("Writing Chunk data (from RAM) failed");
880  }
881  #elif defined(WIN32)
882  SetFilePointer(pFile->hFileWrite, ulWritePos, NULL/*32 bit*/, FILE_BEGIN);
883  DWORD dwBytesWritten;
884  WriteFile(pFile->hFileWrite, pChunkData, NewChunkSize, &dwBytesWritten, NULL);
885  if (dwBytesWritten != NewChunkSize) {
886  throw Exception("Writing Chunk data (from RAM) failed");
887  }
888  #else
889  fseek(pFile->hFileWrite, ulWritePos, SEEK_SET);
890  if (fwrite(pChunkData, 1, NewChunkSize, pFile->hFileWrite) != NewChunkSize) {
891  throw Exception("Writing Chunk data (from RAM) failed");
892  }
893  #endif // POSIX
894  } else {
895  // move chunk data from the end of the file to the appropriate position
896  int8_t* pCopyBuffer = new int8_t[4096];
897  unsigned long ulToMove = (NewChunkSize < CurrentChunkSize) ? NewChunkSize : CurrentChunkSize;
898  #if defined(WIN32)
899  DWORD iBytesMoved = 1; // we have to pass it via pointer to the Windows API, thus the correct size must be ensured
900  #else
901  int iBytesMoved = 1;
902  #endif
903  for (unsigned long ulOffset = 0; ulToMove > 0 && iBytesMoved > 0; ulOffset += iBytesMoved, ulToMove -= iBytesMoved) {
904  iBytesMoved = (ulToMove < 4096) ? ulToMove : 4096;
905  #if POSIX
906  lseek(pFile->hFileRead, ulStartPos + ulCurrentDataOffset + ulOffset, SEEK_SET);
907  iBytesMoved = read(pFile->hFileRead, pCopyBuffer, iBytesMoved);
908  lseek(pFile->hFileWrite, ulWritePos + ulOffset, SEEK_SET);
909  iBytesMoved = write(pFile->hFileWrite, pCopyBuffer, iBytesMoved);
910  #elif defined(WIN32)
911  SetFilePointer(pFile->hFileRead, ulStartPos + ulCurrentDataOffset + ulOffset, NULL/*32 bit*/, FILE_BEGIN);
912  ReadFile(pFile->hFileRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
913  SetFilePointer(pFile->hFileWrite, ulWritePos + ulOffset, NULL/*32 bit*/, FILE_BEGIN);
914  WriteFile(pFile->hFileWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
915  #else
916  fseek(pFile->hFileRead, ulStartPos + ulCurrentDataOffset + ulOffset, SEEK_SET);
917  iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved, pFile->hFileRead);
918  fseek(pFile->hFileWrite, ulWritePos + ulOffset, SEEK_SET);
919  iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved, pFile->hFileWrite);
920  #endif
921  }
922  delete[] pCopyBuffer;
923  if (iBytesMoved < 0) throw Exception("Writing Chunk data (from file) failed");
924  }
925 
926  // update this chunk's header
927  CurrentChunkSize = NewChunkSize;
928  WriteHeader(ulOriginalPos);
929 
930  __notify_progress(pProgress, 1.0); // notify done
931 
932  // update chunk's position pointers
933  ulStartPos = ulOriginalPos + CHUNK_HEADER_SIZE;
934  ulPos = 0;
935 
936  // add pad byte if needed
937  if ((ulStartPos + NewChunkSize) % 2 != 0) {
938  const char cPadByte = 0;
939  #if POSIX
940  lseek(pFile->hFileWrite, ulStartPos + NewChunkSize, SEEK_SET);
941  write(pFile->hFileWrite, &cPadByte, 1);
942  #elif defined(WIN32)
943  SetFilePointer(pFile->hFileWrite, ulStartPos + NewChunkSize, NULL/*32 bit*/, FILE_BEGIN);
944  DWORD dwBytesWritten;
945  WriteFile(pFile->hFileWrite, &cPadByte, 1, &dwBytesWritten, NULL);
946  #else
947  fseek(pFile->hFileWrite, ulStartPos + NewChunkSize, SEEK_SET);
948  fwrite(&cPadByte, 1, 1, pFile->hFileWrite);
949  #endif
950  return ulStartPos + NewChunkSize + 1;
951  }
952 
953  return ulStartPos + NewChunkSize;
954  }
955 
957  ulPos = 0;
958  }
959 
960 
961 
962 // *************** List ***************
963 // *
964 
965  List::List(File* pFile) : Chunk(pFile) {
966  #if DEBUG
967  std::cout << "List::List(File* pFile)" << std::endl;
968  #endif // DEBUG
969  pSubChunks = NULL;
970  pSubChunksMap = NULL;
971  }
972 
973  List::List(File* pFile, unsigned long StartPos, List* Parent)
974  : Chunk(pFile, StartPos, Parent) {
975  #if DEBUG
976  std::cout << "List::List(File*,ulong,bool,List*)" << std::endl;
977  #endif // DEBUG
978  pSubChunks = NULL;
979  pSubChunksMap = NULL;
980  ReadHeader(StartPos);
981  ulStartPos = StartPos + LIST_HEADER_SIZE;
982  }
983 
984  List::List(File* pFile, List* pParent, uint32_t uiListID)
985  : Chunk(pFile, pParent, CHUNK_ID_LIST, 0) {
986  pSubChunks = NULL;
987  pSubChunksMap = NULL;
988  ListType = uiListID;
989  }
990 
992  #if DEBUG
993  std::cout << "List::~List()" << std::endl;
994  #endif // DEBUG
995  DeleteChunkList();
996  }
997 
999  if (pSubChunks) {
1000  ChunkList::iterator iter = pSubChunks->begin();
1001  ChunkList::iterator end = pSubChunks->end();
1002  while (iter != end) {
1003  delete *iter;
1004  iter++;
1005  }
1006  delete pSubChunks;
1007  pSubChunks = NULL;
1008  }
1009  if (pSubChunksMap) {
1010  delete pSubChunksMap;
1011  pSubChunksMap = NULL;
1012  }
1013  }
1014 
1027  #if DEBUG
1028  std::cout << "List::GetSubChunk(uint32_t)" << std::endl;
1029  #endif // DEBUG
1030  if (!pSubChunksMap) LoadSubChunks();
1031  return (*pSubChunksMap)[ChunkID];
1032  }
1033 
1046  #if DEBUG
1047  std::cout << "List::GetSubList(uint32_t)" << std::endl;
1048  #endif // DEBUG
1049  if (!pSubChunks) LoadSubChunks();
1050  ChunkList::iterator iter = pSubChunks->begin();
1051  ChunkList::iterator end = pSubChunks->end();
1052  while (iter != end) {
1053  if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
1054  List* l = (List*) *iter;
1055  if (l->GetListType() == ListType) return l;
1056  }
1057  iter++;
1058  }
1059  return NULL;
1060  }
1061 
1071  #if DEBUG
1072  std::cout << "List::GetFirstSubChunk()" << std::endl;
1073  #endif // DEBUG
1074  if (!pSubChunks) LoadSubChunks();
1075  ChunksIterator = pSubChunks->begin();
1076  return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1077  }
1078 
1087  #if DEBUG
1088  std::cout << "List::GetNextSubChunk()" << std::endl;
1089  #endif // DEBUG
1090  if (!pSubChunks) return NULL;
1091  ChunksIterator++;
1092  return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1093  }
1094 
1105  #if DEBUG
1106  std::cout << "List::GetFirstSubList()" << std::endl;
1107  #endif // DEBUG
1108  if (!pSubChunks) LoadSubChunks();
1109  ListIterator = pSubChunks->begin();
1110  ChunkList::iterator end = pSubChunks->end();
1111  while (ListIterator != end) {
1112  if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST) return (List*) *ListIterator;
1113  ListIterator++;
1114  }
1115  return NULL;
1116  }
1117 
1127  #if DEBUG
1128  std::cout << "List::GetNextSubList()" << std::endl;
1129  #endif // DEBUG
1130  if (!pSubChunks) return NULL;
1131  if (ListIterator == pSubChunks->end()) return NULL;
1132  ListIterator++;
1133  ChunkList::iterator end = pSubChunks->end();
1134  while (ListIterator != end) {
1135  if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST) return (List*) *ListIterator;
1136  ListIterator++;
1137  }
1138  return NULL;
1139  }
1140 
1144  unsigned int List::CountSubChunks() {
1145  if (!pSubChunks) LoadSubChunks();
1146  return pSubChunks->size();
1147  }
1148 
1153  unsigned int List::CountSubChunks(uint32_t ChunkID) {
1154  unsigned int result = 0;
1155  if (!pSubChunks) LoadSubChunks();
1156  ChunkList::iterator iter = pSubChunks->begin();
1157  ChunkList::iterator end = pSubChunks->end();
1158  while (iter != end) {
1159  if ((*iter)->GetChunkID() == ChunkID) {
1160  result++;
1161  }
1162  iter++;
1163  }
1164  return result;
1165  }
1166 
1170  unsigned int List::CountSubLists() {
1171  return CountSubChunks(CHUNK_ID_LIST);
1172  }
1173 
1178  unsigned int List::CountSubLists(uint32_t ListType) {
1179  unsigned int result = 0;
1180  if (!pSubChunks) LoadSubChunks();
1181  ChunkList::iterator iter = pSubChunks->begin();
1182  ChunkList::iterator end = pSubChunks->end();
1183  while (iter != end) {
1184  if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
1185  List* l = (List*) *iter;
1186  if (l->GetListType() == ListType) result++;
1187  }
1188  iter++;
1189  }
1190  return result;
1191  }
1192 
1206  Chunk* List::AddSubChunk(uint32_t uiChunkID, uint uiBodySize) {
1207  if (uiBodySize == 0) throw Exception("Chunk body size must be at least 1 byte");
1208  if (!pSubChunks) LoadSubChunks();
1209  Chunk* pNewChunk = new Chunk(pFile, this, uiChunkID, 0);
1210  pSubChunks->push_back(pNewChunk);
1211  (*pSubChunksMap)[uiChunkID] = pNewChunk;
1212  pNewChunk->Resize(uiBodySize);
1214  pFile->LogAsResized(this);
1215  return pNewChunk;
1216  }
1217 
1229  void List::MoveSubChunk(Chunk* pSrc, Chunk* pDst) {
1230  if (!pSubChunks) LoadSubChunks();
1231  pSubChunks->remove(pSrc);
1232  ChunkList::iterator iter = find(pSubChunks->begin(), pSubChunks->end(), pDst);
1233  pSubChunks->insert(iter, pSrc);
1234  }
1235 
1244  void List::MoveSubChunk(Chunk* pSrc, List* pNewParent) {
1245  if (pNewParent == this || !pNewParent) return;
1246  if (!pSubChunks) LoadSubChunks();
1247  if (!pNewParent->pSubChunks) pNewParent->LoadSubChunks();
1248  pSubChunks->remove(pSrc);
1249  pNewParent->pSubChunks->push_back(pSrc);
1250  // update chunk id map of this List
1251  if ((*pSubChunksMap)[pSrc->GetChunkID()] == pSrc) {
1252  pSubChunksMap->erase(pSrc->GetChunkID());
1253  // try to find another chunk of the same chunk ID
1254  ChunkList::iterator iter = pSubChunks->begin();
1255  ChunkList::iterator end = pSubChunks->end();
1256  for (; iter != end; ++iter) {
1257  if ((*iter)->GetChunkID() == pSrc->GetChunkID()) {
1258  (*pSubChunksMap)[pSrc->GetChunkID()] = *iter;
1259  break; // we're done, stop search
1260  }
1261  }
1262  }
1263  // update chunk id map of other list
1264  if (!(*pNewParent->pSubChunksMap)[pSrc->GetChunkID()])
1265  (*pNewParent->pSubChunksMap)[pSrc->GetChunkID()] = pSrc;
1266  }
1267 
1277  List* List::AddSubList(uint32_t uiListType) {
1278  if (!pSubChunks) LoadSubChunks();
1279  List* pNewListChunk = new List(pFile, this, uiListType);
1280  pSubChunks->push_back(pNewListChunk);
1281  (*pSubChunksMap)[CHUNK_ID_LIST] = pNewListChunk;
1283  pFile->LogAsResized(this);
1284  return pNewListChunk;
1285  }
1286 
1297  void List::DeleteSubChunk(Chunk* pSubChunk) {
1298  if (!pSubChunks) LoadSubChunks();
1299  pSubChunks->remove(pSubChunk);
1300  if ((*pSubChunksMap)[pSubChunk->GetChunkID()] == pSubChunk) {
1301  pSubChunksMap->erase(pSubChunk->GetChunkID());
1302  // try to find another chunk of the same chunk ID
1303  ChunkList::iterator iter = pSubChunks->begin();
1304  ChunkList::iterator end = pSubChunks->end();
1305  for (; iter != end; ++iter) {
1306  if ((*iter)->GetChunkID() == pSubChunk->GetChunkID()) {
1307  (*pSubChunksMap)[pSubChunk->GetChunkID()] = *iter;
1308  break; // we're done, stop search
1309  }
1310  }
1311  }
1312  delete pSubChunk;
1313  }
1314 
1315  void List::ReadHeader(unsigned long fPos) {
1316  #if DEBUG
1317  std::cout << "List::Readheader(ulong) ";
1318  #endif // DEBUG
1319  Chunk::ReadHeader(fPos);
1320  if (CurrentChunkSize < 4) return;
1322  #if POSIX
1323  lseek(pFile->hFileRead, fPos + CHUNK_HEADER_SIZE, SEEK_SET);
1324  read(pFile->hFileRead, &ListType, 4);
1325  #elif defined(WIN32)
1326  SetFilePointer(pFile->hFileRead, fPos + CHUNK_HEADER_SIZE, NULL/*32 bit*/, FILE_BEGIN);
1327  DWORD dwBytesRead;
1328  ReadFile(pFile->hFileRead, &ListType, 4, &dwBytesRead, NULL);
1329  #else
1330  fseek(pFile->hFileRead, fPos + CHUNK_HEADER_SIZE, SEEK_SET);
1331  fread(&ListType, 4, 1, pFile->hFileRead);
1332  #endif // POSIX
1333  #if DEBUG
1334  std::cout << "listType=" << convertToString(ListType) << std::endl;
1335  #endif // DEBUG
1336  if (!pFile->bEndianNative) {
1337  //swapBytes_32(&ListType);
1338  }
1339  }
1340 
1341  void List::WriteHeader(unsigned long fPos) {
1342  // the four list type bytes officially belong the chunk's body in the RIFF format
1343  NewChunkSize += 4;
1344  Chunk::WriteHeader(fPos);
1345  NewChunkSize -= 4; // just revert the +4 incrementation
1346  #if POSIX
1347  lseek(pFile->hFileWrite, fPos + CHUNK_HEADER_SIZE, SEEK_SET);
1348  write(pFile->hFileWrite, &ListType, 4);
1349  #elif defined(WIN32)
1350  SetFilePointer(pFile->hFileWrite, fPos + CHUNK_HEADER_SIZE, NULL/*32 bit*/, FILE_BEGIN);
1351  DWORD dwBytesWritten;
1352  WriteFile(pFile->hFileWrite, &ListType, 4, &dwBytesWritten, NULL);
1353  #else
1354  fseek(pFile->hFileWrite, fPos + CHUNK_HEADER_SIZE, SEEK_SET);
1355  fwrite(&ListType, 4, 1, pFile->hFileWrite);
1356  #endif // POSIX
1357  }
1358 
1359  void List::LoadSubChunks(progress_t* pProgress) {
1360  #if DEBUG
1361  std::cout << "List::LoadSubChunks()";
1362  #endif // DEBUG
1363  if (!pSubChunks) {
1364  pSubChunks = new ChunkList();
1365  pSubChunksMap = new ChunkMap();
1366  #if defined(WIN32)
1367  if (pFile->hFileRead == INVALID_HANDLE_VALUE) return;
1368  #else
1369  if (!pFile->hFileRead) return;
1370  #endif
1371  unsigned long uiOriginalPos = GetPos();
1372  SetPos(0); // jump to beginning of list chunk body
1373  while (RemainingBytes() >= CHUNK_HEADER_SIZE) {
1374  Chunk* ck;
1375  uint32_t ckid;
1376  Read(&ckid, 4, 1);
1377  #if DEBUG
1378  std::cout << " ckid=" << convertToString(ckid) << std::endl;
1379  #endif // DEBUG
1380  if (ckid == CHUNK_ID_LIST) {
1381  ck = new RIFF::List(pFile, ulStartPos + ulPos - 4, this);
1383  }
1384  else { // simple chunk
1385  ck = new RIFF::Chunk(pFile, ulStartPos + ulPos - 4, this);
1387  }
1388  pSubChunks->push_back(ck);
1389  (*pSubChunksMap)[ckid] = ck;
1390  if (GetPos() % 2 != 0) SetPos(1, RIFF::stream_curpos); // jump over pad byte
1391  }
1392  SetPos(uiOriginalPos); // restore position before this call
1393  }
1394  __notify_progress(pProgress, 1.0); // notify done
1395  }
1396 
1398  const int n = CountSubLists();
1399  int i = 0;
1400  for (List* pList = GetFirstSubList(); pList; pList = GetNextSubList(), ++i) {
1401  // divide local progress into subprogress
1402  progress_t subprogress;
1403  __divide_progress(pProgress, &subprogress, n, i);
1404  // do the actual work
1405  pList->LoadSubChunksRecursively(&subprogress);
1406  }
1407  __notify_progress(pProgress, 1.0); // notify done
1408  }
1409 
1425  unsigned long List::WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset, progress_t* pProgress) {
1426  const unsigned long ulOriginalPos = ulWritePos;
1427  ulWritePos += LIST_HEADER_SIZE;
1428 
1429  if (pFile->Mode != stream_mode_read_write)
1430  throw Exception("Cannot write list chunk, file has to be opened in read+write mode");
1431 
1432  // write all subchunks (including sub list chunks) recursively
1433  if (pSubChunks) {
1434  int i = 0;
1435  const int n = pSubChunks->size();
1436  for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter, ++i) {
1437  // divide local progress into subprogress for loading current Instrument
1438  progress_t subprogress;
1439  __divide_progress(pProgress, &subprogress, n, i);
1440  // do the actual work
1441  ulWritePos = (*iter)->WriteChunk(ulWritePos, ulCurrentDataOffset, &subprogress);
1442  }
1443  }
1444 
1445  // update this list chunk's header
1446  CurrentChunkSize = NewChunkSize = ulWritePos - ulOriginalPos - LIST_HEADER_SIZE;
1447  WriteHeader(ulOriginalPos);
1448 
1449  // offset of this list chunk in new written file may have changed
1450  ulStartPos = ulOriginalPos + LIST_HEADER_SIZE;
1451 
1452  __notify_progress(pProgress, 1.0); // notify done
1453 
1454  return ulWritePos;
1455  }
1456 
1459  if (pSubChunks) {
1460  for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter) {
1461  (*iter)->__resetPos();
1462  }
1463  }
1464  }
1465 
1470  return convertToString(ListType);
1471  }
1472 
1473 
1474 
1475 // *************** File ***************
1476 // *
1477 
1492  File::File(uint32_t FileType)
1493  : List(this), bIsNewFile(true), Layout(layout_standard)
1494  {
1495  #if defined(WIN32)
1496  hFileRead = hFileWrite = INVALID_HANDLE_VALUE;
1497  #else
1498  hFileRead = hFileWrite = 0;
1499  #endif
1500  Mode = stream_mode_closed;
1501  bEndianNative = true;
1503  ListType = FileType;
1504  }
1505 
1514  File::File(const String& path)
1515  : List(this), Filename(path), bIsNewFile(false), Layout(layout_standard)
1516  {
1517  #if DEBUG
1518  std::cout << "File::File("<<path<<")" << std::endl;
1519  #endif // DEBUG
1520  bEndianNative = true;
1521  try {
1522  __openExistingFile(path);
1523  if (ChunkID != CHUNK_ID_RIFF && ChunkID != CHUNK_ID_RIFX) {
1524  throw RIFF::Exception("Not a RIFF file");
1525  }
1526  }
1527  catch (...) {
1528  Cleanup();
1529  throw;
1530  }
1531  }
1532 
1558  File::File(const String& path, uint32_t FileType, endian_t Endian, layout_t layout)
1559  : List(this), Filename(path), bIsNewFile(false), Layout(layout)
1560  {
1561  SetByteOrder(Endian);
1562  try {
1563  __openExistingFile(path, &FileType);
1564  }
1565  catch (...) {
1566  Cleanup();
1567  throw;
1568  }
1569  }
1570 
1581  void File::__openExistingFile(const String& path, uint32_t* FileType) {
1582  ResizedChunks.clear();
1583  #if POSIX
1584  hFileRead = hFileWrite = open(path.c_str(), O_RDONLY | O_NONBLOCK);
1585  if (hFileRead == -1) {
1586  hFileRead = hFileWrite = 0;
1587  String sError = strerror(errno);
1588  throw RIFF::Exception("Can't open \"" + path + "\": " + sError);
1589  }
1590  #elif defined(WIN32)
1591  hFileRead = hFileWrite = CreateFile(
1592  path.c_str(), GENERIC_READ,
1593  FILE_SHARE_READ | FILE_SHARE_WRITE,
1594  NULL, OPEN_EXISTING,
1595  FILE_ATTRIBUTE_NORMAL |
1596  FILE_FLAG_RANDOM_ACCESS, NULL
1597  );
1598  if (hFileRead == INVALID_HANDLE_VALUE) {
1599  hFileRead = hFileWrite = INVALID_HANDLE_VALUE;
1600  throw RIFF::Exception("Can't open \"" + path + "\"");
1601  }
1602  #else
1603  hFileRead = hFileWrite = fopen(path.c_str(), "rb");
1604  if (!hFileRead) throw RIFF::Exception("Can't open \"" + path + "\"");
1605  #endif // POSIX
1606  Mode = stream_mode_read;
1607  switch (Layout) {
1608  case layout_standard: // this is a normal RIFF file
1610  ReadHeader(0);
1611  if (FileType && ChunkID != *FileType)
1612  throw RIFF::Exception("Invalid file container ID");
1613  break;
1614  case layout_flat: // non-standard RIFF-alike file
1615  ulStartPos = 0;
1616  NewChunkSize = CurrentChunkSize = GetFileSize();
1617  if (FileType) {
1618  uint32_t ckid;
1619  if (Read(&ckid, 4, 1) != 4) {
1620  throw RIFF::Exception("Invalid file header ID (premature end of header)");
1621  } else if (ckid != *FileType) {
1622  String s = " (expected '" + convertToString(*FileType) + "' but got '" + convertToString(ckid) + "')";
1623  throw RIFF::Exception("Invalid file header ID" + s);
1624  }
1625  SetPos(0); // reset to first byte of file
1626  }
1627  LoadSubChunks();
1628  break;
1629  }
1630  }
1631 
1633  return Filename;
1634  }
1635 
1636  void File::SetFileName(const String& path) {
1637  Filename = path;
1638  }
1639 
1641  return Mode;
1642  }
1643 
1645  return Layout;
1646  }
1647 
1659  if (NewMode != Mode) {
1660  switch (NewMode) {
1661  case stream_mode_read:
1662  #if POSIX
1663  if (hFileRead) close(hFileRead);
1664  hFileRead = hFileWrite = open(Filename.c_str(), O_RDONLY | O_NONBLOCK);
1665  if (hFileRead == -1) {
1666  hFileRead = hFileWrite = 0;
1667  String sError = strerror(errno);
1668  throw Exception("Could not (re)open file \"" + Filename + "\" in read mode: " + sError);
1669  }
1670  #elif defined(WIN32)
1671  if (hFileRead != INVALID_HANDLE_VALUE) CloseHandle(hFileRead);
1672  hFileRead = hFileWrite = CreateFile(
1673  Filename.c_str(), GENERIC_READ,
1674  FILE_SHARE_READ | FILE_SHARE_WRITE,
1675  NULL, OPEN_EXISTING,
1676  FILE_ATTRIBUTE_NORMAL |
1677  FILE_FLAG_RANDOM_ACCESS,
1678  NULL
1679  );
1680  if (hFileRead == INVALID_HANDLE_VALUE) {
1681  hFileRead = hFileWrite = INVALID_HANDLE_VALUE;
1682  throw Exception("Could not (re)open file \"" + Filename + "\" in read mode");
1683  }
1684  #else
1685  if (hFileRead) fclose(hFileRead);
1686  hFileRead = hFileWrite = fopen(Filename.c_str(), "rb");
1687  if (!hFileRead) throw Exception("Could not (re)open file \"" + Filename + "\" in read mode");
1688  #endif
1689  __resetPos(); // reset read/write position of ALL 'Chunk' objects
1690  break;
1692  #if POSIX
1693  if (hFileRead) close(hFileRead);
1694  hFileRead = hFileWrite = open(Filename.c_str(), O_RDWR | O_NONBLOCK);
1695  if (hFileRead == -1) {
1696  hFileRead = hFileWrite = open(Filename.c_str(), O_RDONLY | O_NONBLOCK);
1697  String sError = strerror(errno);
1698  throw Exception("Could not open file \"" + Filename + "\" in read+write mode: " + sError);
1699  }
1700  #elif defined(WIN32)
1701  if (hFileRead != INVALID_HANDLE_VALUE) CloseHandle(hFileRead);
1702  hFileRead = hFileWrite = CreateFile(
1703  Filename.c_str(),
1704  GENERIC_READ | GENERIC_WRITE,
1705  FILE_SHARE_READ,
1706  NULL, OPEN_ALWAYS,
1707  FILE_ATTRIBUTE_NORMAL |
1708  FILE_FLAG_RANDOM_ACCESS,
1709  NULL
1710  );
1711  if (hFileRead == INVALID_HANDLE_VALUE) {
1712  hFileRead = hFileWrite = CreateFile(
1713  Filename.c_str(), GENERIC_READ,
1714  FILE_SHARE_READ | FILE_SHARE_WRITE,
1715  NULL, OPEN_EXISTING,
1716  FILE_ATTRIBUTE_NORMAL |
1717  FILE_FLAG_RANDOM_ACCESS,
1718  NULL
1719  );
1720  throw Exception("Could not (re)open file \"" + Filename + "\" in read+write mode");
1721  }
1722  #else
1723  if (hFileRead) fclose(hFileRead);
1724  hFileRead = hFileWrite = fopen(Filename.c_str(), "r+b");
1725  if (!hFileRead) {
1726  hFileRead = hFileWrite = fopen(Filename.c_str(), "rb");
1727  throw Exception("Could not open file \"" + Filename + "\" in read+write mode");
1728  }
1729  #endif
1730  __resetPos(); // reset read/write position of ALL 'Chunk' objects
1731  break;
1732  case stream_mode_closed:
1733  #if POSIX
1734  if (hFileRead) close(hFileRead);
1735  if (hFileWrite) close(hFileWrite);
1736  #elif defined(WIN32)
1737  if (hFileRead != INVALID_HANDLE_VALUE) CloseHandle(hFileRead);
1738  if (hFileWrite != INVALID_HANDLE_VALUE) CloseHandle(hFileWrite);
1739  #else
1740  if (hFileRead) fclose(hFileRead);
1741  if (hFileWrite) fclose(hFileWrite);
1742  #endif
1743  hFileRead = hFileWrite = 0;
1744  break;
1745  default:
1746  throw Exception("Unknown file access mode");
1747  }
1748  Mode = NewMode;
1749  return true;
1750  }
1751  return false;
1752  }
1753 
1764  #if WORDS_BIGENDIAN
1765  bEndianNative = Endian != endian_little;
1766  #else
1767  bEndianNative = Endian != endian_big;
1768  #endif
1769  }
1770 
1782  void File::Save(progress_t* pProgress) {
1783  //TODO: implementation for the case where first chunk is not a global container (List chunk) is not implemented yet (i.e. Korg files)
1784  if (Layout == layout_flat)
1785  throw Exception("Saving a RIFF file with layout_flat is not implemented yet");
1786 
1787  // make sure the RIFF tree is built (from the original file)
1788  {
1789  // divide progress into subprogress
1790  progress_t subprogress;
1791  __divide_progress(pProgress, &subprogress, 3.f, 0.f); // arbitrarily subdivided into 1/3 of total progress
1792  // do the actual work
1793  LoadSubChunksRecursively(&subprogress);
1794  // notify subprogress done
1795  __notify_progress(&subprogress, 1.f);
1796  }
1797 
1798  // reopen file in write mode
1800 
1801  // to be able to save the whole file without loading everything into
1802  // RAM and without having to store the data in a temporary file, we
1803  // enlarge the file with the sum of all _positive_ chunk size
1804  // changes, move current data towards the end of the file with the
1805  // calculated sum and finally update / rewrite the file by copying
1806  // the old data back to the right position at the beginning of the file
1807 
1808  // first we sum up all positive chunk size changes (and skip all negative ones)
1809  unsigned long ulPositiveSizeDiff = 0;
1810  for (std::set<Chunk*>::const_iterator iter = ResizedChunks.begin(), end = ResizedChunks.end(); iter != end; ++iter) {
1811  if ((*iter)->GetNewSize() == 0) {
1812  throw Exception("There is at least one empty chunk (zero size): " + __resolveChunkPath(*iter));
1813  }
1814  unsigned long newSizePadded = (*iter)->GetNewSize() + (*iter)->GetNewSize() % 2;
1815  unsigned long oldSizePadded = (*iter)->GetSize() + (*iter)->GetSize() % 2;
1816  if (newSizePadded > oldSizePadded) ulPositiveSizeDiff += newSizePadded - oldSizePadded;
1817  }
1818 
1819  unsigned long ulWorkingFileSize = GetFileSize();
1820 
1821  // if there are positive size changes...
1822  if (ulPositiveSizeDiff > 0) {
1823  // divide progress into subprogress
1824  progress_t subprogress;
1825  __divide_progress(pProgress, &subprogress, 3.f, 1.f); // arbitrarily subdivided into 1/3 of total progress
1826 
1827  // ... we enlarge this file first ...
1828  ulWorkingFileSize += ulPositiveSizeDiff;
1829  ResizeFile(ulWorkingFileSize);
1830  // ... and move current data by the same amount towards end of file.
1831  int8_t* pCopyBuffer = new int8_t[4096];
1832  const unsigned long ulFileSize = GetSize() + RIFF_HEADER_SIZE;
1833  #if defined(WIN32)
1834  DWORD iBytesMoved = 1; // we have to pass it via pointer to the Windows API, thus the correct size must be ensured
1835  #else
1836  int iBytesMoved = 1;
1837  #endif
1838  for (unsigned long ulPos = ulFileSize, iNotif = 0; iBytesMoved > 0; ++iNotif) {
1839  iBytesMoved = (ulPos < 4096) ? ulPos : 4096;
1840  ulPos -= iBytesMoved;
1841  #if POSIX
1842  lseek(hFileRead, ulPos, SEEK_SET);
1843  iBytesMoved = read(hFileRead, pCopyBuffer, iBytesMoved);
1844  lseek(hFileWrite, ulPos + ulPositiveSizeDiff, SEEK_SET);
1845  iBytesMoved = write(hFileWrite, pCopyBuffer, iBytesMoved);
1846  #elif defined(WIN32)
1847  SetFilePointer(hFileRead, ulPos, NULL/*32 bit*/, FILE_BEGIN);
1848  ReadFile(hFileRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1849  SetFilePointer(hFileWrite, ulPos + ulPositiveSizeDiff, NULL/*32 bit*/, FILE_BEGIN);
1850  WriteFile(hFileWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1851  #else
1852  fseek(hFileRead, ulPos, SEEK_SET);
1853  iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved, hFileRead);
1854  fseek(hFileWrite, ulPos + ulPositiveSizeDiff, SEEK_SET);
1855  iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved, hFileWrite);
1856  #endif
1857  if (!(iNotif % 8) && iBytesMoved > 0)
1858  __notify_progress(&subprogress, float(ulFileSize - ulPos) / float(ulFileSize));
1859  }
1860  delete[] pCopyBuffer;
1861  if (iBytesMoved < 0) throw Exception("Could not modify file while trying to enlarge it");
1862 
1863  __notify_progress(&subprogress, 1.f); // notify subprogress done
1864  }
1865 
1866  // rebuild / rewrite complete RIFF tree ...
1867 
1868  // divide progress into subprogress
1869  progress_t subprogress;
1870  __divide_progress(pProgress, &subprogress, 3.f, 2.f); // arbitrarily subdivided into 1/3 of total progress
1871  // do the actual work
1872  unsigned long ulTotalSize = WriteChunk(0, ulPositiveSizeDiff, &subprogress);
1873  unsigned long ulActualSize = __GetFileSize(hFileWrite);
1874  // notify subprogress done
1875  __notify_progress(&subprogress, 1.f);
1876 
1877  // resize file to the final size
1878  if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);
1879 
1880  // forget all resized chunks
1881  ResizedChunks.clear();
1882 
1883  __notify_progress(pProgress, 1.0); // notify done
1884  }
1885 
1900  void File::Save(const String& path, progress_t* pProgress) {
1901  //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
1902 
1903  //TODO: implementation for the case where first chunk is not a global container (List chunk) is not implemented yet (i.e. Korg files)
1904  if (Layout == layout_flat)
1905  throw Exception("Saving a RIFF file with layout_flat is not implemented yet");
1906 
1907  // make sure the RIFF tree is built (from the original file)
1908  {
1909  // divide progress into subprogress
1910  progress_t subprogress;
1911  __divide_progress(pProgress, &subprogress, 2.f, 0.f); // arbitrarily subdivided into 1/2 of total progress
1912  // do the actual work
1913  LoadSubChunksRecursively(&subprogress);
1914  // notify subprogress done
1915  __notify_progress(&subprogress, 1.f);
1916  }
1917 
1919  // open the other (new) file for writing and truncate it to zero size
1920  #if POSIX
1921  hFileWrite = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
1922  if (hFileWrite == -1) {
1924  String sError = strerror(errno);
1925  throw Exception("Could not open file \"" + path + "\" for writing: " + sError);
1926  }
1927  #elif defined(WIN32)
1928  hFileWrite = CreateFile(
1929  path.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
1930  NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL |
1931  FILE_FLAG_RANDOM_ACCESS, NULL
1932  );
1933  if (hFileWrite == INVALID_HANDLE_VALUE) {
1935  throw Exception("Could not open file \"" + path + "\" for writing");
1936  }
1937  #else
1938  hFileWrite = fopen(path.c_str(), "w+b");
1939  if (!hFileWrite) {
1941  throw Exception("Could not open file \"" + path + "\" for writing");
1942  }
1943  #endif // POSIX
1944  Mode = stream_mode_read_write;
1945 
1946  // write complete RIFF tree to the other (new) file
1947  unsigned long ulTotalSize;
1948  {
1949  // divide progress into subprogress
1950  progress_t subprogress;
1951  __divide_progress(pProgress, &subprogress, 2.f, 1.f); // arbitrarily subdivided into 1/2 of total progress
1952  // do the actual work
1953  ulTotalSize = WriteChunk(0, 0, &subprogress);
1954  // notify subprogress done
1955  __notify_progress(&subprogress, 1.f);
1956  }
1957  unsigned long ulActualSize = __GetFileSize(hFileWrite);
1958 
1959  // resize file to the final size (if the file was originally larger)
1960  if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);
1961 
1962  // forget all resized chunks
1963  ResizedChunks.clear();
1964 
1965  #if POSIX
1966  if (hFileWrite) close(hFileWrite);
1967  #elif defined(WIN32)
1968  if (hFileWrite != INVALID_HANDLE_VALUE) CloseHandle(hFileWrite);
1969  #else
1970  if (hFileWrite) fclose(hFileWrite);
1971  #endif
1973 
1974  // associate new file with this File object from now on
1975  Filename = path;
1976  bIsNewFile = false;
1977  Mode = (stream_mode_t) -1; // Just set it to an undefined mode ...
1978  SetMode(stream_mode_read_write); // ... so SetMode() has to reopen the file handles.
1979 
1980  __notify_progress(pProgress, 1.0); // notify done
1981  }
1982 
1983  void File::ResizeFile(unsigned long ulNewSize) {
1984  #if POSIX
1985  if (ftruncate(hFileWrite, ulNewSize) < 0)
1986  throw Exception("Could not resize file \"" + Filename + "\"");
1987  #elif defined(WIN32)
1988  if (
1989  SetFilePointer(hFileWrite, ulNewSize, NULL/*32 bit*/, FILE_BEGIN) == INVALID_SET_FILE_POINTER ||
1990  !SetEndOfFile(hFileWrite)
1991  ) throw Exception("Could not resize file \"" + Filename + "\"");
1992  #else
1993  # error Sorry, this version of libgig only supports POSIX and Windows systems yet.
1994  # error Reason: portable implementation of RIFF::File::ResizeFile() is missing (yet)!
1995  #endif
1996  }
1997 
1999  #if DEBUG
2000  std::cout << "File::~File()" << std::endl;
2001  #endif // DEBUG
2002  Cleanup();
2003  }
2004 
2009  bool File::IsNew() const {
2010  return bIsNewFile;
2011  }
2012 
2013  void File::Cleanup() {
2014  #if POSIX
2015  if (hFileRead) close(hFileRead);
2016  #elif defined(WIN32)
2017  if (hFileRead != INVALID_HANDLE_VALUE) CloseHandle(hFileRead);
2018  #else
2019  if (hFileRead) fclose(hFileRead);
2020  #endif // POSIX
2021  DeleteChunkList();
2022  pFile = NULL;
2023  ResizedChunks.clear();
2024  }
2025 
2026  void File::LogAsResized(Chunk* pResizedChunk) {
2027  ResizedChunks.insert(pResizedChunk);
2028  }
2029 
2030  void File::UnlogResized(Chunk* pResizedChunk) {
2031  ResizedChunks.erase(pResizedChunk);
2032  }
2033 
2034  unsigned long File::GetFileSize() {
2035  return __GetFileSize(hFileRead);
2036  }
2037 
2038  #if POSIX
2039  unsigned long File::__GetFileSize(int hFile) {
2040  struct stat filestat;
2041  fstat(hFile, &filestat);
2042  long size = filestat.st_size;
2043  return size;
2044  }
2045  #elif defined(WIN32)
2046  unsigned long File::__GetFileSize(HANDLE hFile) {
2047  DWORD dwSize = ::GetFileSize(hFile, NULL /*32bit*/);
2048  if (dwSize == INVALID_FILE_SIZE)
2049  throw Exception("Windows FS error: could not determine file size");
2050  return dwSize;
2051  }
2052  #else // standard C functions
2053  unsigned long File::__GetFileSize(FILE* hFile) {
2054  long curpos = ftell(hFile);
2055  fseek(hFile, 0, SEEK_END);
2056  long size = ftell(hFile);
2057  fseek(hFile, curpos, SEEK_SET);
2058  return size;
2059  }
2060  #endif
2061 
2062 
2063 // *************** Exception ***************
2064 // *
2065 
2067  std::cout << "RIFF::Exception: " << Message << std::endl;
2068  }
2069 
2070 
2071 // *************** functions ***************
2072 // *
2073 
2080  return PACKAGE;
2081  }
2082 
2088  return VERSION;
2089  }
2090 
2091 } // namespace RIFF
unsigned long WriteUint32(uint32_t *pData, unsigned long WordCount=1)
Writes WordCount number of 32 Bit unsigned integer words from the buffer pointed by pData to the chun...
Definition: RIFF.cpp:649
int16_t ReadInt16()
Reads one 16 Bit signed integer word and increments the position within the chunk.
Definition: RIFF.cpp:693
bool bEndianNative
Definition: RIFF.h:378
void UnlogResized(Chunk *pResizedChunk)
Definition: RIFF.cpp:2030
List * pParent
Definition: RIFF.h:248
#define CHUNK_ID_RIFX
Definition: RIFF.h:95
stream_whence_t
File stream position dependent to these relations.
Definition: RIFF.h:159
unsigned long Read(void *pData, unsigned long WordCount, unsigned long WordSize)
Reads WordCount number of data words with given WordSize and copies it into a buffer pointed by pData...
Definition: RIFF.cpp:296
Chunk * GetFirstSubChunk()
Returns the first subchunk within the list.
Definition: RIFF.cpp:1070
String libraryName()
Returns the name of this C++ library.
Definition: RIFF.cpp:2079
virtual unsigned long WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset, progress_t *pProgress=NULL)
Write list chunk persistently e.g.
Definition: RIFF.cpp:1425
File(uint32_t FileType)
Create new RIFF file.
Definition: RIFF.cpp:1492
unsigned long WriteUint16(uint16_t *pData, unsigned long WordCount=1)
Writes WordCount number of 16 Bit unsigned integer words from the buffer pointed by pData to the chun...
Definition: RIFF.cpp:558
uint32_t GetChunkID()
Chunk ID in unsigned integer representation.
Definition: RIFF.h:209
layout_t Layout
An ordinary RIFF file is always set to layout_standard.
Definition: RIFF.h:380
void(* callback)(progress_t *)
Callback function pointer which has to be assigned to a function for progress notification.
Definition: RIFF.h:192
layout_t GetLayout() const
Definition: RIFF.cpp:1644
String GetFileName()
Definition: RIFF.cpp:1632
void ReadHeader(unsigned long fPos)
Definition: RIFF.cpp:1315
stream_state_t
Current state of the file stream.
Definition: RIFF.h:152
unsigned long SetPos(unsigned long Where, stream_whence_t Whence=stream_start)
Sets the position within the chunk body, thus within the data portion of the chunk (in bytes)...
Definition: RIFF.cpp:215
bool bIsNewFile
Definition: RIFF.h:379
void ReadString(String &s, int size)
Reads a null-padded string of size characters and copies it into the string s.
Definition: RIFF.cpp:628
#define LIST_HEADER_SIZE
Definition: RIFF.h:112
void WriteHeader(unsigned long fPos)
Definition: RIFF.cpp:1341
String libraryVersion()
Returns version of this C++ library.
Definition: RIFF.cpp:2087
List * GetSubList(uint32_t ListType)
Returns sublist chunk with list type ListType within this chunk list.
Definition: RIFF.cpp:1045
void DeleteSubChunk(Chunk *pSubChunk)
Removes a sub chunk.
Definition: RIFF.cpp:1297
unsigned long WriteInt16(int16_t *pData, unsigned long WordCount=1)
Writes WordCount number of 16 Bit signed integer words from the buffer pointed by pData to the chunk&#39;...
Definition: RIFF.cpp:521
std::string String
Definition: Akai.h:59
#define CHUNK_HEADER_SIZE
Definition: RIFF.h:111
int hFileWrite
handle / descriptor for writing to (some) file
Definition: RIFF.h:369
String Filename
Definition: RIFF.h:377
unsigned long RemainingBytes()
Returns the number of bytes left to read in the chunk body.
Definition: RIFF.cpp:247
List * GetFirstSubList()
Returns the first sublist within the list (that is a subchunk with chunk ID "LIST").
Definition: RIFF.cpp:1104
stream_mode_t
Whether file stream is open in read or in read/write mode.
Definition: RIFF.h:145
std::list< Chunk * > ChunkList
Definition: RIFF.h:325
std::string String
Definition: RIFF.h:140
unsigned long GetPos()
Position within the chunk data body.
Definition: RIFF.h:214
void SetByteOrder(endian_t Endian)
Set the byte order to be used when saving.
Definition: RIFF.cpp:1763
RIFF List Chunk.
Definition: RIFF.h:302
#define CHUNK_ID_RIFF
Definition: RIFF.h:94
File * pFile
Definition: RIFF.h:249
int8_t ReadInt8()
Reads one 8 Bit signed integer word and increments the position within the chunk. ...
Definition: RIFF.cpp:660
void ReadHeader(unsigned long fPos)
Definition: RIFF.cpp:118
String GetListTypeString()
Returns string representation of the lists&#39;s id.
Definition: RIFF.cpp:1469
ChunkList::iterator ListIterator
Definition: RIFF.h:332
float __range_min
Only for internal usage, do not modify!
Definition: RIFF.h:195
unsigned long ulPos
Definition: RIFF.h:251
unsigned long WriteInt32(int32_t *pData, unsigned long WordCount=1)
Writes WordCount number of 32 Bit signed integer words from the buffer pointed by pData to the chunk&#39;...
Definition: RIFF.cpp:595
void DeleteChunkList()
Definition: RIFF.cpp:998
Chunk * GetSubChunk(uint32_t ChunkID)
Returns subchunk with chunk ID ChunkID within this chunk list.
Definition: RIFF.cpp:1026
Chunk * GetNextSubChunk()
Returns the next subchunk within the list.
Definition: RIFF.cpp:1086
unsigned long ReadSceptical(void *pData, unsigned long WordCount, unsigned long WordSize)
Just an internal wrapper for the main Read() method with additional Exception throwing on errors...
Definition: RIFF.cpp:409
int32_t ReadInt32()
Reads one 32 Bit signed integer word and increments the position within the chunk.
Definition: RIFF.cpp:727
virtual void Save(progress_t *pProgress=NULL)
Save changes to same file.
Definition: RIFF.cpp:1782
layout_t
General chunk structure of a file.
Definition: RIFF.h:174
stream_state_t GetState()
Returns the current state of the chunk object.
Definition: RIFF.cpp:265
Ordinary RIFF Chunk.
Definition: RIFF.h:205
uint32_t GetListType()
Returns unsigned integer representation of the list&#39;s ID.
Definition: RIFF.h:306
#define RIFF_HEADER_SIZE
Definition: RIFF.h:113
uint32_t ReadUint32()
Reads one 32 Bit unsigned integer word and increments the position within the chunk.
Definition: RIFF.cpp:744
ChunkList::iterator ChunksIterator
Definition: RIFF.h:331
unsigned long ulStartPos
Definition: RIFF.h:250
void * custom
This pointer can be used for arbitrary data.
Definition: RIFF.h:194
unsigned long Write(void *pData, unsigned long WordCount, unsigned long WordSize)
Writes WordCount number of data words with given WordSize from the buffer pointed by pData...
Definition: RIFF.cpp:359
Used for indicating the progress of a certain task.
Definition: RIFF.h:191
ChunkList * pSubChunks
Definition: RIFF.h:329
virtual unsigned long WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset, progress_t *pProgress=NULL)
Write chunk persistently e.g.
Definition: RIFF.cpp:864
Chunk * AddSubChunk(uint32_t uiChunkID, uint uiBodySize)
Creates a new sub chunk.
Definition: RIFF.cpp:1206
void PrintMessage()
Definition: RIFF.cpp:2066
int hFileRead
handle / descriptor for reading from file
Definition: RIFF.h:368
Not a "real" RIFF file: First chunk in file is an ordinary data chunk, not a List chunk...
Definition: RIFF.h:176
ChunkMap * pSubChunksMap
Definition: RIFF.h:330
virtual ~Chunk()
Definition: RIFF.cpp:113
void LogAsResized(Chunk *pResizedChunk)
Definition: RIFF.cpp:2026
virtual void __resetPos()
Sets Chunk&#39;s read/write position to zero.
Definition: RIFF.cpp:956
uint16_t ReadUint16()
Reads one 16 Bit unsigned integer word and increments the position within the chunk.
Definition: RIFF.cpp:710
virtual void __resetPos()
Sets List Chunk&#39;s read/write position to zero and causes all sub chunks to do the same...
Definition: RIFF.cpp:1457
uint32_t CurrentChunkSize
Definition: RIFF.h:246
endian_t
Alignment of data bytes in memory (system dependant).
Definition: RIFF.h:167
void SetFileName(const String &path)
Definition: RIFF.cpp:1636
void * LoadChunkData()
Load chunk body into RAM.
Definition: RIFF.cpp:774
unsigned long WriteInt8(int8_t *pData, unsigned long WordCount=1)
Writes WordCount number of 8 Bit signed integer words from the buffer pointed by pData to the chunk&#39;s...
Definition: RIFF.cpp:447
void LoadSubChunksRecursively(progress_t *pProgress=NULL)
Definition: RIFF.cpp:1397
Standard RIFF file layout: First chunk in file is a List chunk which contains all other chunks and th...
Definition: RIFF.h:175
unsigned long GetSize() const
Chunk size in bytes (without header, thus the chunk data body)
Definition: RIFF.h:212
RIFF File.
Definition: RIFF.h:351
List * AddSubList(uint32_t uiListType)
Creates a new list sub chunk.
Definition: RIFF.cpp:1277
#define CHUNK_ID_LIST
Definition: RIFF.h:96
RIFF specific classes and definitions.
Definition: RIFF.h:135
bool IsNew() const
Returns true if this file has been created new from scratch and has not been stored to disk yet...
Definition: RIFF.cpp:2009
List(File *pFile, unsigned long StartPos, List *Parent)
Definition: RIFF.cpp:973
void MoveSubChunk(Chunk *pSrc, Chunk *pDst)
Moves a sub chunk witin this list.
Definition: RIFF.cpp:1229
unsigned int CountSubChunks()
Returns number of subchunks within the list.
Definition: RIFF.cpp:1144
virtual ~List()
Definition: RIFF.cpp:991
String convertToString(uint32_t word)
Definition: RIFF.h:282
bool SetMode(stream_mode_t NewMode)
Change file access mode.
Definition: RIFF.cpp:1658
float __range_max
Only for internal usage, do not modify!
Definition: RIFF.h:196
Will be thrown whenever an error occurs while handling a RIFF file.
Definition: RIFF.h:406
unsigned long WriteUint8(uint8_t *pData, unsigned long WordCount=1)
Writes WordCount number of 8 Bit unsigned integer words from the buffer pointed by pData to the chunk...
Definition: RIFF.cpp:484
void LoadSubChunks(progress_t *pProgress=NULL)
Definition: RIFF.cpp:1359
stream_mode_t GetMode()
Definition: RIFF.cpp:1640
void ReleaseChunkData()
Free loaded chunk body from RAM.
Definition: RIFF.cpp:818
virtual ~File()
Definition: RIFF.cpp:1998
unsigned int CountSubLists()
Returns number of sublists within the list.
Definition: RIFF.cpp:1170
String GetChunkIDString()
Returns the String representation of the chunk&#39;s ID (e.g.
Definition: RIFF.cpp:199
uint32_t NewChunkSize
Definition: RIFF.h:247
void WriteHeader(unsigned long fPos)
Definition: RIFF.cpp:161
uint32_t ChunkID
Definition: RIFF.h:245
std::map< uint32_t, RIFF::Chunk * > ChunkMap
Definition: RIFF.h:324
void Resize(int iNewSize)
Resize chunk.
Definition: RIFF.cpp:843
List * GetNextSubList()
Returns the next sublist (that is a subchunk with chunk ID "LIST") within the list.
Definition: RIFF.cpp:1126
Chunk(File *pFile, unsigned long StartPos, List *Parent)
Definition: RIFF.cpp:86
uint8_t ReadUint8()
Reads one 8 Bit unsigned integer word and increments the position within the chunk.
Definition: RIFF.cpp:676
uint32_t ListType
Definition: RIFF.h:328