CLAM-Development  1.4.0
SDIFFile.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG)
3  * UNIVERSITAT POMPEU FABRA
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
22 #include "SDIFFile.hxx"
23 #include "ErrOpenFile.hxx" // error handling on openfile error
24 #include "ErrFormat.hxx" // error handling on format error
25 
26 #ifdef WIN32
27  #include <io.h>
28  #include <fcntl.h>
29 #else
30  #include <unistd.h>
31  #include <sys/types.h>
32  #include <sys/stat.h>
33  #include <fcntl.h>
34 #endif
35 
36 
37 namespace SDIF
38 {
39 
40  File::File(const char* filename,Mode mode):
41  mSkipData(false),
42  mFirstAccess(true),
43  mMode(mode),
44  mFile(-1),
45  mSize(0)
46  {
47  mpName = new char[ strlen(filename)+1 ];
48  strncpy( mpName, filename, strlen(filename)+1 );
49  }
50 
52  {
53  delete [] mpName;
54  }
55 
56  void File::Open(void)
57  {
58  int mode = 0;
59  if (mMode==eInput) mode = O_RDONLY; // defined in <fcntl.h>
60  if (mMode==eOutput) mode = O_WRONLY|O_CREAT|O_TRUNC;
61  if (mMode==eFullDuplex) mode = O_RDWR;
62 
63  #ifdef WIN32
64  mode |= O_BINARY;
65  #endif
66 
67  if (mFile==-1)
68  {
69  //Open the file only if unopened
70  mFile = open(mpName,mode,0644);
71 
72  if (mFile==-1)
73  {
74  // if open file error
75  throw CLAM::ErrOpenFile(mpName); // throw filename
76  }
77  }
78  mSize = lseek(mFile,0,SEEK_END);
79  lseek(mFile,0,SEEK_SET);
80  }
81 
82  /* close audio file */
83  void File::Close(void)
84  {
85  if (mFile!=-1)
86  {
87  //Close the file only if unopened
88  close(mFile);
89  mFile=-1;
90  }
91  }
92 
93  void File::Read(Storage& storage)
94  {
95  while (!Done()) {
96  Frame* frame = new Frame;
97  Read(*frame);
98  storage.Add(frame);
99  }
100  }
101 
102  void File::Write(const Storage& storage)
103  {
104  typedef std::list<Frame*>::const_iterator iterator;
105 
106  iterator it = storage.Begin();
107  iterator end = storage.End();
108 
109  while (it!=end)
110  {
111  Frame* frame = *it;
112  Write(*frame);
113  it++;
114  }
115  }
116 
117  void File::Read(TypeId& type)
118  {
119  Read(type.mData,4);
120  }
121 
122  void File::Write(const TypeId& type)
123  {
124  Write(type.mData,4);
125  }
126 
127  void File::Read(FrameHeader& header)
128  {
129  Read(header.mType);
130  TRead(header.mSize);
131  }
132 
133  void File::Write(const FrameHeader& header)
134  {
135  Write(header.mType);
136  TWrite(header.mSize);
137  }
138 
139  void File::Read(DataFrameHeader& header)
140  {
141  Read((FrameHeader&)header);
142  TRead(header.mTime);
143  TRead(header.mStreamId);
144  TRead(header.mnMatrices);
145  }
146 
147  void File::Write(const DataFrameHeader& header)
148  {
149  Write((FrameHeader&)header);
150  TWrite(header.mTime);
151  TWrite(header.mStreamId);
152  TWrite(header.mnMatrices);
153  }
154 
155  void File::Read(Frame& frame)
156  {
157  if (mFirstAccess)
158  {
159  mFirstAccess = false;
160  OpeningsFrame opening;
161  Read(opening);
162  }
163 
165 
166  Read(frame.mHeader);
167 
168  CLAM::TInt32 readSize = frame.mHeader.mSize;
169  frame.mHeader.mSize = DataFrameHeader::SizeInFile();
170 
171  int tmp = frame.mHeader.mnMatrices;
172  frame.mHeader.mnMatrices = 0; // frame.Add will increase this
173  for (int i=0;i<tmp;i++)
174  {
175  MatrixHeader header;
176  File::Read(header);
177  Matrix* pMatrix = 0;
178  switch (header.mDataType)
179  {
180  case eFloat32:
181  pMatrix = new ConcreteMatrix<CLAM::TFloat32>(header); break;
182  case eFloat64:
183  pMatrix = new ConcreteMatrix<CLAM::TFloat64>(header); break;
184  case eInt32:
185  pMatrix = new ConcreteMatrix<CLAM::TInt32>(header); break;
186  case eInt64:
187  pMatrix = new ConcreteMatrix<CLAM::TInt64>(header); break;
188  case eUTF8byte:
189  pMatrix = new ConcreteMatrix<TUTF8byte>(header); break;
190  case eByte:
191  pMatrix = new ConcreteMatrix<CLAM::TByte>(header); break;
192  default:
193  // +++ how do we handle unknown types ???
194  std::cerr << "SDIFFile.Read(Frame). Received a matrix header with an unknown type: <" << header.mDataType << ">" << std::endl;
195  pMatrix = new ConcreteMatrix<CLAM::TByte>(header); break;
196  };
197  File::ReadMatrixData(*pMatrix);
198  frame.Add(pMatrix);
199  }
200 
201  if (readSize-frame.mHeader.mSize==8)
202  {
203  // This is a kludge to read SDIF files as generated by the
204  // SMSTools smscommandline application. The framesize as
205  // specified in the frame header of these files has been
206  // calculate incorrectly (the size of the frame type and
207  // frame size fields itself are included in the total size)
208  // This result in the frame size as read from the file
209  // (readSize) being the real (calculated during read) frame
210  // size frame.mHeader.mSize + 8. If we encounter this, and
211  // the following data a frame header as used in the SMS-SDIF
212  // files, then we silently accept and continue.
213  int tmp = Pos();
214  if (Done())
215  {
216  readSize -= 8;
217  }
218  else
219  {
220  TypeId t;
221  Read(t);
222  Pos(tmp);
223  if (t=="1STF" || t=="1FQ0" || t=="1TRC")
224  {
225  readSize -= 8;
226  }
227  }
228  }
229  CLAM_ASSERT(frame.mHeader.mSize == readSize,
230  "Reading Frame, calculated size does not match read size");
231  CLAM_ASSERT(Pos()-p == readSize,
232  "Reading Frame, size-in-file does not match read size");
233  }
234 
235  void File::Write(const Frame& frame)
236  {
237  if (mFirstAccess)
238  {
239  mFirstAccess = false;
240  OpeningsFrame opening;
241  Write(opening);
242  }
243 
244  CLAM::TInt32 writeSize = frame.mHeader.mSize;
246 
247  Write(frame.mHeader);
248 
249  typedef std::list<Matrix*>::const_iterator iterator;
250 
251  iterator it = frame.mMatrixList.begin();
252  iterator end = frame.mMatrixList.end();
253 
254  while (it!=end)
255  {
256  Matrix* pMatrix = *it;
257  File::Write(*pMatrix);
258  it++;
259  }
260 
261  CLAM_ASSERT(Pos()-p == writeSize,
262  "Incorrect framesize written in SDIF file");
263  }
264 
265  void File::Read(OpeningsFrame& frame)
266  {
267  Read(frame.mHeader);
268  TRead(frame.mSpecVersion);
269  TRead(frame.mStandardTypesVersion);
270  }
271 
272  void File::Write(const OpeningsFrame& frame)
273  {
274  Write(frame.mHeader);
275  TWrite(frame.mSpecVersion);
276  TWrite(frame.mStandardTypesVersion);
277  }
278 
279  void File::Read(MatrixHeader& header)
280  {
281  Read(header.mType);
282  CLAM::TInt32 tmp;
283  TRead(tmp);
284  header.mDataType = (DataType) tmp;
285  TRead(header.mnRows);
286  TRead(header.mnColumns);
287  }
288 
289  void File::Write(const MatrixHeader& header)
290  {
291  Write(header.mType);
292  CLAM::TInt32 tmp = header.mDataType;
293  TWrite(tmp);
294  TWrite(header.mnRows);
295  TWrite(header.mnColumns);
296  }
297 
298  void File::Read(Matrix& matrix)
299  {
300  Read(matrix.mHeader);
301  if (mSkipData)
302  {
303  SkipMatrixData(matrix);
304  } else {
305  ReadMatrixData(matrix);
306  }
307  }
308 
309  void File::Write(const Matrix& matrix)
310  {
311  Write(matrix.mHeader);
312  WriteMatrixData(matrix);
313  }
314 
315  void File::SkipMatrixData(const Matrix& matrix)
316  {
317  CLAM::TUInt32 size = matrix.mHeader.mnColumns*matrix.mHeader.mnRows*
318  ((matrix.mHeader.mDataType)&0xFF);
319  CLAM::TUInt32 padding = 8-size&7;
320  Pos(Pos()+size+padding);
321  }
322 
323  #ifdef linux
324  #include <byteswap.h>
325  #endif
326 
327  #ifdef WIN32
328  #include <stdlib.h>
329  #endif
330 
332  {
333  #if defined linux
334  return bswap_16(val);
335  /*#elif defined WIN32
336  CLAM::TUInt16 ret;
337  _swab((char*)(&val),(char*)(&ret),16);
338  return ret;*/
339  #else
340  return (val>>8)|(val<<8);
341  #endif
342  }
343 
345  {
346  #if defined linux
347  return bswap_32(val);
348  /*#elif defined WIN32
349  CLAM::TUInt32 ret;
350  _swab((char*)(&val),(char*)(&ret),32);
351  return ret;*/
352  #else
353  CLAM::TUInt32 cp = val;
354  CLAM::TByte* ptr=(CLAM::TByte*) &cp;
355  static CLAM::TByte tmp;
356  tmp=ptr[0]; ptr[0]=ptr[3]; ptr[3]=tmp;
357  tmp=ptr[1]; ptr[1]=ptr[2]; ptr[2]=tmp;
358  return cp;
359  #endif
360  }
361 
363  {
364  #if defined linux
365  return bswap_64(val);
366  /*#elif defined WIN32
367  CLAM::TUInt64 ret;
368  _swab((char*)(&val),(char*)(&ret),64);
369  return ret;*/
370  #else
371  CLAM::TUInt64 cp = val;
372  CLAM::TByte* ptr=(CLAM::TByte*) &cp;
373  static CLAM::TByte tmp;
374  tmp=ptr[0]; ptr[0]=ptr[7]; ptr[7]=tmp;
375  tmp=ptr[1]; ptr[1]=ptr[6]; ptr[6]=tmp;
376  tmp=ptr[2]; ptr[2]=ptr[5]; ptr[5]=tmp;
377  tmp=ptr[3]; ptr[3]=ptr[4]; ptr[4]=tmp;
378  return cp;
379  #endif
380  }
381 
382  void File::_FixByteOrder(
383  CLAM::TByte* ptr,CLAM::TUInt32 nElems,CLAM::TUInt32 elemSize)
384  {
385  switch (elemSize)
386  {
387  case 1: return;
388  case 2:
389  {
390  CLAM::TUInt16* fptr = (CLAM::TUInt16*) ptr;
391  for (CLAM::TUInt32 i=0;i<nElems;i++)
392  {
393  *fptr = Swap(*fptr);
394  fptr++;
395  }
396  return;
397  }
398  case 4:
399  {
400  CLAM::TUInt32* fptr = (CLAM::TUInt32*) ptr;
401  for (CLAM::TUInt32 i=0;i<nElems;i++)
402  {
403  *fptr = Swap(*fptr);
404  fptr++;
405  }
406  return;
407  }
408  case 8:
409  {
410  CLAM::TUInt64* fptr = (CLAM::TUInt64*) ptr;
411  for (CLAM::TUInt32 i=0;i<nElems;i++)
412  {
413  *fptr = Swap(*fptr);
414  fptr++;
415  }
416  return;
417  }
418  default:
419  std::cerr << "SDIFFile._FixByteOrder; Received an unsupported element size. size <" << elemSize << ">" << std::endl;
420  throw;
421  }
422  }
423 
424  void File::ReadMatrixData(Matrix& matrix)
425  {
426  CLAM::TByte dum[8];
427  CLAM::TUInt32 nElems = matrix.mHeader.mnColumns*matrix.mHeader.mnRows;
428  CLAM::TUInt32 elemSize = matrix.mHeader.mDataType&0xFF;
429  CLAM::TUInt32 size = nElems*elemSize;
430 
431  CLAM::TUInt32 padding = 8-size&7;
432 
433  matrix.Resize(nElems);
434  matrix.SetSize(nElems);
435 
436  Read((CLAM::TByte*) matrix.GetPtr(),size);
437  FixByteOrder((CLAM::TByte*) matrix.GetPtr(),nElems,elemSize);
438 
439  Read(dum,padding);
440  }
441 
442  void File::WriteMatrixData(const Matrix& matrix)
443  {
444  CLAM::TByte dum[8];
445  CLAM::TUInt32 nElems = matrix.mHeader.mnColumns*matrix.mHeader.mnRows;
446  CLAM::TUInt32 elemSize = matrix.mHeader.mDataType&0xFF;
447  CLAM::TUInt32 size = nElems*elemSize;
448 
449  CLAM::TUInt32 padding = 8-size&7;
450 
451  CLAM::TByte tmp[1024];
452  const CLAM::TByte *ptr = (const CLAM::TByte*) const_cast<Matrix&>(matrix).GetPtr();
453  while (size)
454  {
455  int blocksize = size;
456  if (blocksize>1024) blocksize = 1024;
457  memcpy(tmp,ptr,blocksize);
458 
459  FixByteOrder(tmp,blocksize/elemSize,elemSize);
460  Write((CLAM::TByte*) tmp,blocksize);
461 
462  ptr+=blocksize;
463  size-=blocksize;
464  }
465 
466  Write(dum,padding);
467  }
468 
469 }
470