Logo Search packages:      
Sourcecode: xcdroast version File versions  Download package

wav_id.c

/*
      wav_id.c
      14.07.99 tn

      machine-independent (work both on big and little endian)
      code to check if we have valid wavheader that is configured
      for cd-quality (16 bit, stereo, 44.1kHz)

      01.04.04 steve wahl

      Do correct RIFF parsing, don't assume a static header style.
      Code borrowed from cdrecord.
*/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "largefile.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <glib.h>
#include "xcdroast.h"

typedef struct {
      guchar      ckid[4];
      guchar      cksize[4];
} chunk_t;

typedef struct {
      guchar      wave[4];
} riff_chunk;

typedef struct {
      guchar      fmt_tag[2];
      guchar      channels[2];
      guchar      sample_rate[4];
      guchar      av_byte_rate[4];
      guchar      block_size[2];
      guchar      bits_per_sample[2];
} fmt_chunk;

#define     WAV_RIFF_MAGIC          "RIFF"            /* Magic for file format     */
#define     WAV_WAVE_MAGIC          "WAVE"            /* Magic for Waveform Audio  */
#define     WAV_FMT_MAGIC           "fmt "            /* Start of Waveform format  */
#define     WAV_DATA_MAGIC          "data"            /* Start of data chunk       */
#define     WAV_FORMAT_PCM          0x0001            /* Linear PCM format         */
#define     WAV_FORMAT_ULAW         0x0101            /* American ISDN Telephonie  */
#define     WAV_FORMAT_ALAW         0x0102            /* International ISDN Tel.   */
#define     WAV_FORMAT_ADPCM  0x0103            /* ADPCM format              */

#define     le_a_to_u_short(a)      ((unsigned short) \
                        ((((unsigned char*) a)[0]       & 0xFF) | \
                         (((unsigned char*) a)[1] << 8  & 0xFF00)))

#ifdef      __STDC__
#define     le_a_to_u_long(a) ((unsigned long) \
                        ((((unsigned char*) a)[0]       & 0xFF) | \
                         (((unsigned char*) a)[1] << 8  & 0xFF00) | \
                         (((unsigned char*) a)[2] << 16 & 0xFF0000) | \
                         (((unsigned char*) a)[3] << 24 & 0xFF000000UL)))
#else
#define     le_a_to_u_long(a) ((unsigned long) \
                        ((((unsigned char*) a)[0]       & 0xFF) | \
                         (((unsigned char*) a)[1] << 8  & 0xFF00) | \
                         (((unsigned char*) a)[2] << 16 & 0xFF0000) | \
                         (((unsigned char*) a)[3] << 24 & 0xFF000000)))
#endif

/* check if valid wav-header */
/* endian independent version */
/* return number of bytes if valid, 0 if not */
/* if offset is non NULL, place offset in file to base of wave data there */
/* leaves file pointer at begining of wave data if valid */

off_t is_std_wav_file(gint f, off_t *offset)
{
      chunk_t           chunk;
      riff_chunk  riff;
      fmt_chunk   fmt;
      struct stat sb;
      off_t       cursor;
      gint        gotFormat;
      mode_t            mode;
      off_t       size;

      /*
       * First check if a bad guy tries to call wavsize()
       * with an unappropriate file descriptor.
       * return 0 in this case.
       */

      if (isatty(f))
            return (0);
      if (fstat(f, &sb) < 0)
            return (0);
      mode = sb.st_mode & S_IFMT;
      if (!S_ISREG(mode) && !S_ISBLK(mode) && !S_ISCHR(mode))
            return (0);

      cursor = (off_t)0;
      lseek(f, cursor, SEEK_SET);
      gotFormat = FALSE;

      for (;;) {
            if (read(f, &chunk, sizeof (chunk)) != sizeof (chunk))
                  goto err;
            size = (off_t)le_a_to_u_long(chunk.cksize);

            if (strncmp((char *)chunk.ckid, WAV_RIFF_MAGIC, 4) == 0) {
                  /*
                   * We found (first) RIFF header. Check if a WAVE
                   * magic follows. Set up size to be able to skip
                   * past this header.
                   */
                  if (read(f, &riff, sizeof (riff)) != sizeof (riff))
                        goto err;
                  if (strncmp((char *)riff.wave, WAV_WAVE_MAGIC, 4) != 0)
                        goto err;
                  size = (off_t)sizeof (riff);

            } else if (strncmp((char *)chunk.ckid, WAV_FMT_MAGIC, 4) == 0) {
                  /*
                   * We found WAVE "fmt " header. Check size (if it is
                   * valid for a WAVE file) and coding whether it is
                   * useable for a CD. 
                   */
                  if (size < (off_t)sizeof (fmt)) goto err;
                  if (sizeof (fmt) != read(f, &fmt, sizeof (fmt))) goto err;
                  if (le_a_to_u_short(fmt.channels) != 2 ||
                      le_a_to_u_long(fmt.sample_rate) != 44100 ||
                      le_a_to_u_short(fmt.bits_per_sample) != 16) {
                        goto err;
                  }
                  gotFormat = TRUE;

            } else if (strncmp((char *)chunk.ckid, WAV_DATA_MAGIC, 4) == 0) {
                  /*
                   * We found WAVE "data" header. This contains the
                   * size value of the audio part.
                   */
                  if (!gotFormat) {
                        goto err;
                  }
                  if ((cursor + size + sizeof (chunk)) > sb.st_size)
                        size = sb.st_size - (cursor  + sizeof (chunk));
                  if (offset)
                        *offset = cursor + sizeof (chunk) ;
                  return (size);
            }
            cursor += size + sizeof (chunk);
            lseek(f, cursor, SEEK_SET);   /* Skip over current chunk */
      }
err:
      lseek(f, (off_t)0L, SEEK_SET);
      return (0);
}





Generated by  Doxygen 1.6.0   Back to index