Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/freealut-1.1.0/src/alutLoader.c @ 58

Last change on this file since 58 was 14, checked in by landauf, 17 years ago

added freealut

File size: 12.0 KB
Line 
1#include "alutInternal.h"
2#include <ctype.h>
3
4/****************************************************************************/
5
6typedef enum
7{
8  LittleEndian,
9  BigEndian,
10  UnknwonEndian                 /* has anybody still a PDP11? :-) */
11} Endianess;
12
13/* test from Harbison & Steele, "C - A Reference Manual", section 6.1.2 */
14static Endianess
15endianess (void)
16{
17  union
18  {
19    long l;
20    char c[sizeof (long)];
21  } u;
22
23  u.l = 1;
24  return (u.c[0] == 1) ? LittleEndian :
25    ((u.c[sizeof (long) - 1] == 1) ? BigEndian : UnknwonEndian);
26}
27
28/****************************************************************************/
29
30static int
31safeToLower (int c)
32{
33  return isupper (c) ? tolower (c) : c;
34}
35
36static int
37hasSuffixIgnoringCase (const char *string, const char *suffix)
38{
39  const char *stringPointer = string;
40  const char *suffixPointer = suffix;
41
42  if (suffix[0] == '\0')
43    {
44      return 1;
45    }
46
47  while (*stringPointer != '\0')
48    {
49      stringPointer++;
50    }
51
52  while (*suffixPointer != '\0')
53    {
54      suffixPointer++;
55    }
56
57  if (stringPointer - string < suffixPointer - suffix)
58    {
59      return 0;
60    }
61
62  while (safeToLower (*--suffixPointer) == safeToLower (*--stringPointer))
63    {
64      if (suffixPointer == suffix)
65        {
66          return 1;
67        }
68    }
69
70  return 0;
71}
72
73static BufferData *
74loadWavFile (InputStream *stream)
75{
76  ALboolean found_header = AL_FALSE;
77  UInt32LittleEndian chunkLength;
78  Int32BigEndian magic;
79  UInt16LittleEndian audioFormat;
80  UInt16LittleEndian numChannels;
81  UInt32LittleEndian sampleFrequency;
82  UInt32LittleEndian byteRate;
83  UInt16LittleEndian blockAlign;
84  UInt16LittleEndian bitsPerSample;
85  Codec *codec = _alutCodecLinear;
86
87  if (!_alutInputStreamReadUInt32LE (stream, &chunkLength) ||
88      !_alutInputStreamReadInt32BE (stream, &magic))
89    {
90      return NULL;
91    }
92
93  if (magic != 0x57415645)      /* "WAVE" */
94    {
95      _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE);
96      return NULL;
97    }
98
99  while (1)
100    {
101      if (!_alutInputStreamReadInt32BE (stream, &magic) ||
102          !_alutInputStreamReadUInt32LE (stream, &chunkLength))
103        {
104          return NULL;
105        }
106
107      if (magic == 0x666d7420)  /* "fmt " */
108        {
109          found_header = AL_TRUE;
110
111          if (chunkLength < 16)
112            {
113              _alutSetError (ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA);
114              return NULL;
115            }
116
117          if (!_alutInputStreamReadUInt16LE (stream, &audioFormat) ||
118              !_alutInputStreamReadUInt16LE (stream, &numChannels) ||
119              !_alutInputStreamReadUInt32LE (stream, &sampleFrequency) ||
120              !_alutInputStreamReadUInt32LE (stream, &byteRate) ||
121              !_alutInputStreamReadUInt16LE (stream, &blockAlign) ||
122              !_alutInputStreamReadUInt16LE (stream, &bitsPerSample))
123            {
124              return NULL;
125            }
126
127          if (!_alutInputStreamSkip (stream, chunkLength - 16))
128            {
129              return NULL;
130            }
131
132          switch (audioFormat)
133            {
134            case 1:            /* PCM */
135              codec = (bitsPerSample == 8
136                       || endianess () ==
137                       LittleEndian) ? _alutCodecLinear : _alutCodecPCM16;
138              break;
139            case 7:            /* uLaw */
140              bitsPerSample *= 2;       /* ToDo: ??? */
141              codec = _alutCodecULaw;
142              break;
143            default:
144              _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE);
145              return NULL;
146            }
147        }
148      else if (magic == 0x64617461)     /* "data" */
149        {
150          ALvoid *data;
151          if (!found_header)
152            {
153              /* ToDo: A bit wrong to check here, fmt chunk could come later... */
154              _alutSetError (ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA);
155              return NULL;
156            }
157          data = _alutInputStreamRead (stream, chunkLength);
158          if (data == NULL)
159            {
160              return NULL;
161            }
162          return codec (data, chunkLength, numChannels, bitsPerSample,
163                        (ALfloat) sampleFrequency);
164        }
165      else
166        {
167          if (!_alutInputStreamSkip (stream, chunkLength))
168            {
169              return NULL;
170            }
171        }
172
173      if ((chunkLength & 1) && !_alutInputStreamEOF (stream)
174          && !_alutInputStreamSkip (stream, 1))
175        {
176          return NULL;
177        }
178    }
179}
180
181static BufferData *
182loadAUFile (InputStream *stream)
183{
184  Int32BigEndian dataOffset;    /* byte offset to data part, minimum 24 */
185  Int32BigEndian len;           /* number of bytes in the data part, -1 = not known */
186  Int32BigEndian encoding;      /* encoding of the data part, see AUEncoding */
187  Int32BigEndian sampleFrequency;       /* number of samples per second */
188  Int32BigEndian numChannels;   /* number of interleaved channels */
189  size_t length;
190  Codec *codec;
191  char *data;
192  ALint bitsPerSample;
193
194  if (!_alutInputStreamReadInt32BE (stream, &dataOffset) ||
195      !_alutInputStreamReadInt32BE (stream, &len) ||
196      !_alutInputStreamReadInt32BE (stream, &encoding) ||
197      !_alutInputStreamReadInt32BE (stream, &sampleFrequency) ||
198      !_alutInputStreamReadInt32BE (stream, &numChannels))
199    {
200      return AL_FALSE;
201    }
202
203  length = (len == -1) ?
204    (_alutInputStreamGetRemainingLength (stream) - AU_HEADER_SIZE -
205     dataOffset) : (size_t) len;
206
207  if (!
208      (dataOffset >= AU_HEADER_SIZE && length > 0 && sampleFrequency >= 1
209       && numChannels >= 1))
210    {
211      _alutSetError (ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA);
212      return AL_FALSE;
213    }
214
215  if (!_alutInputStreamSkip (stream, dataOffset - AU_HEADER_SIZE))
216    {
217      return AL_FALSE;
218    }
219
220  switch (encoding)
221    {
222    case AU_ULAW_8:
223      bitsPerSample = 16;
224      codec = _alutCodecULaw;
225      break;
226    case AU_PCM_8:
227      bitsPerSample = 8;
228      codec = _alutCodecPCM8s;
229      break;
230    case AU_PCM_16:
231      bitsPerSample = 16;
232      codec =
233        (endianess () == BigEndian) ? _alutCodecLinear : _alutCodecPCM16;
234      break;
235    case AU_ALAW_8:
236      bitsPerSample = 16;
237      codec = _alutCodecALaw;
238      break;
239    default:
240      _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE);
241      return AL_FALSE;
242    }
243
244  data = _alutInputStreamRead (stream, length);
245  if (data == NULL)
246    {
247      return NULL;
248    }
249  return codec (data, length, numChannels, bitsPerSample,
250                (ALfloat) sampleFrequency);
251}
252
253static BufferData *
254loadRawFile (InputStream *stream)
255{
256  size_t length = _alutInputStreamGetRemainingLength (stream);
257  ALvoid *data = _alutInputStreamRead (stream, length);
258  if (data == NULL)
259    {
260      return NULL;
261    }
262  /* Guesses */
263  return _alutCodecLinear (data, length, 1, 8, 8000);
264}
265
266static BufferData *
267loadFile (InputStream *stream)
268{
269  const char *fileName;
270  Int32BigEndian magic;
271
272  /* Raw files have no magic number - so use the fileName extension */
273
274  fileName = _alutInputStreamGetFileName (stream);
275  if (fileName != NULL && hasSuffixIgnoringCase (fileName, ".raw"))
276    {
277      return loadRawFile (stream);
278    }
279
280  /* For other file formats, read the quasi-standard four byte magic number */
281  if (!_alutInputStreamReadInt32BE (stream, &magic))
282    {
283      return AL_FALSE;
284    }
285
286  /* Magic number 'RIFF' == Microsoft '.wav' format */
287  if (magic == 0x52494646)
288    {
289      return loadWavFile (stream);
290    }
291
292  /* Magic number '.snd' == Sun & Next's '.au' format */
293  if (magic == 0x2E736E64)
294    {
295      return loadAUFile (stream);
296    }
297
298  _alutSetError (ALUT_ERROR_UNSUPPORTED_FILE_TYPE);
299  return AL_FALSE;
300}
301
302ALuint
303_alutCreateBufferFromInputStream (InputStream *stream)
304{
305  BufferData *bufferData;
306  ALuint buffer;
307
308  if (stream == NULL)
309    {
310      return AL_NONE;
311    }
312
313  bufferData = loadFile (stream);
314  _alutInputStreamDestroy (stream);
315  if (bufferData == NULL)
316    {
317      return AL_NONE;
318    }
319
320  buffer = _alutPassBufferData (bufferData);
321  _alutBufferDataDestroy (bufferData);
322
323  return buffer;
324}
325
326ALuint
327alutCreateBufferFromFile (const char *fileName)
328{
329  InputStream *stream;
330  if (!_alutSanityCheck ())
331    {
332      return AL_NONE;
333    }
334  stream = _alutInputStreamConstructFromFile (fileName);
335  return _alutCreateBufferFromInputStream (stream);
336}
337
338ALuint
339alutCreateBufferFromFileImage (const ALvoid *data, ALsizei length)
340{
341  InputStream *stream;
342  if (!_alutSanityCheck ())
343    {
344      return AL_NONE;
345    }
346  stream = _alutInputStreamConstructFromMemory (data, length);
347  return _alutCreateBufferFromInputStream (stream);
348}
349
350void *
351_alutLoadMemoryFromInputStream (InputStream *stream, ALenum *format,
352                                ALsizei *size, ALfloat *frequency)
353{
354  BufferData *bufferData;
355  ALenum fmt;
356  void *data;
357
358  if (stream == NULL)
359    {
360      return NULL;
361    }
362
363  bufferData = loadFile (stream);
364  if (bufferData == NULL)
365    {
366      _alutInputStreamDestroy (stream);
367      return NULL;
368    }
369  _alutInputStreamDestroy (stream);
370
371  if (!_alutGetFormat (bufferData, &fmt))
372    {
373      _alutBufferDataDestroy (bufferData);
374      return NULL;
375    }
376
377  if (size != NULL)
378    {
379      *size = (ALsizei) _alutBufferDataGetLength (bufferData);
380    }
381
382  if (format != NULL)
383    {
384      *format = fmt;
385    }
386
387  if (frequency != NULL)
388    {
389      *frequency = _alutBufferDataGetSampleFrequency (bufferData);
390    }
391
392  data = _alutBufferDataGetData (bufferData);
393  _alutBufferDataDetachData (bufferData);
394  _alutBufferDataDestroy (bufferData);
395  return data;
396}
397
398ALvoid *
399alutLoadMemoryFromFile (const char *fileName, ALenum *format,
400                        ALsizei *size, ALfloat *frequency)
401{
402  InputStream *stream;
403  if (!_alutSanityCheck ())
404    {
405      return NULL;
406    }
407  stream = _alutInputStreamConstructFromFile (fileName);
408  return _alutLoadMemoryFromInputStream (stream, format, size, frequency);
409}
410
411ALvoid *
412alutLoadMemoryFromFileImage (const ALvoid *data, ALsizei length,
413                             ALenum *format, ALsizei *size,
414                             ALfloat *frequency)
415{
416  InputStream *stream;
417  if (!_alutSanityCheck ())
418    {
419      return NULL;
420    }
421  stream = _alutInputStreamConstructFromMemory (data, length);
422  return _alutLoadMemoryFromInputStream (stream, format, size, frequency);
423}
424
425/*
426  Yukky backwards compatibility crap.
427*/
428
429void
430alutLoadWAVFile (ALbyte *fileName, ALenum *format, void **data, ALsizei *size,
431                 ALsizei *frequency
432#if !defined(__APPLE__)
433                 , ALboolean *loop
434#endif
435  )
436{
437  InputStream *stream;
438  ALfloat freq;
439
440  /* Don't do an _alutSanityCheck () because it's not required in ALUT 0.x.x */
441
442  stream = _alutInputStreamConstructFromFile (fileName);
443  *data = _alutLoadMemoryFromInputStream (stream, format, size, &freq);
444  if (*data == NULL)
445    {
446      return;
447    }
448
449  if (frequency)
450    {
451      *frequency = (ALsizei) freq;
452    }
453
454#if !defined(__APPLE__)
455  if (loop)
456    {
457      *loop = AL_FALSE;
458    }
459#endif
460}
461
462void
463alutLoadWAVMemory (ALbyte *buffer, ALenum *format, void **data, ALsizei *size,
464                   ALsizei *frequency
465#if !defined(__APPLE__)
466                   , ALboolean *loop
467#endif
468  )
469{
470  InputStream *stream;
471  ALfloat freq;
472
473  /* Don't do an _alutSanityCheck () because it's not required in ALUT 0.x.x */
474
475  /* ToDo: Can we do something less insane than passing 0x7FFFFFFF? */
476  stream = _alutInputStreamConstructFromMemory (buffer, 0x7FFFFFFF);
477  _alutLoadMemoryFromInputStream (stream, format, size, &freq);
478  if (*data == NULL)
479    {
480      return;
481    }
482
483  if (frequency)
484    {
485      *frequency = (ALsizei) freq;
486    }
487
488#if !defined(__APPLE__)
489  if (loop)
490    {
491      *loop = AL_FALSE;
492    }
493#endif
494}
495
496void
497alutUnloadWAV (ALenum UNUSED (format), ALvoid *data, ALsizei UNUSED (size),
498               ALsizei UNUSED (frequency))
499{
500  /* Don't do an _alutSanityCheck () because it's not required in ALUT 0.x.x */
501
502  free (data);
503}
504
505const char *
506alutGetMIMETypes (ALenum loader)
507{
508  if (!_alutSanityCheck ())
509    {
510      return NULL;
511    }
512
513  /* We do not distinguish the loaders yet... */
514  switch (loader)
515    {
516    case ALUT_LOADER_BUFFER:
517      return "audio/basic,audio/x-raw,audio/x-wav";
518
519    case ALUT_LOADER_MEMORY:
520      return "audio/basic,audio/x-raw,audio/x-wav";
521
522    default:
523      _alutSetError (ALUT_ERROR_INVALID_ENUM);
524      return NULL;
525    }
526}
Note: See TracBrowser for help on using the repository browser.