/* Copyright (c) 2000  Kevin Sullivan <nite@gis.net>
 *
 * Please refer to the COPYRIGHT file for more information.
 */

/* the main functions in this file are mp3info and ogginfo. They
   extract information such as file size, bitrate, sample frequency,
   and md5 hash from a named file */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>

#include "alias.h"
#include "md5.h"
#include "mp3s.h"
#include "defines.h"

#ifdef MEMWATCH
  #include "memwatch.h"
#endif

/* arrays are indexed using id & bitrate fields from frame header */
/* 1st row is for MPEG-2 (id=0) Layer III, 2nd for MPEG-1 (id=1) Layer III */
int bratetab[2][16] = 
  {
    { 0,  8, 16, 24, 32, 40, 48, 56,  64,  80,  96, 112, 128, 144, 160, -1 },
    { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 }
  };

int freqtab[2][4] =
  {
    { 22050, 24000, 16000, 50000 }, /* MPEG-2 */
    { 44100, 48000, 32000, 50000 }  /* MPEG-1 */
  }; 

/* check for valid mp3 header. Return 1 if ok. */
int checkhdr(hdr_t *h)
{
  if (h->sync != 0xfff ||
      h->layer != 1 ||
      h->brate == 15 ||
      h->freq == 3 ||
      h->emph == 2)
    return(0);
  
  return(1);
}

/* get "real" header info from an mp3 file. The stream f is already
   positioned to skip any id3v2 header, if present */
int getrhdr(int f, hdr_t *r)
{
  unsigned char bw[4];
  int n;

  n = read(f, bw, sizeof(bw));
  if (n < 4) { /* e.g. near EOF */
    return(0);
  }

  buf4tohdr(bw, r);

  if (!checkhdr(r))
  {
    return(0);
  }
  
  return(1);
}

/* convert an array of four bytes into a frame header (hdr_t) structure */
void buf4tohdr(unsigned char *bw, hdr_t *r)
{
  /* Note: to ensure portability, use explicit assignments and shift
     operators, rather than writing binary data directly into the hdr_t
     structure. The difference in efficiency is negligible. -PS */
  r->emph      = (bw[3] & 0x03) >> 0;  
  r->original  = (bw[3] & 0x04) >> 2;  
  r->copyright = (bw[3] & 0x08) >> 3;  
  r->mode_ext  = (bw[3] & 0x30) >> 4;
  r->mode      = (bw[3] & 0xc0) >> 6;
  r->pvt       = (bw[2] & 0x01) >> 0;
  r->pad       = (bw[2] & 0x02) >> 1;
  r->freq      = (bw[2] & 0x0c) >> 2;
  r->brate     = (bw[2] & 0xf0) >> 4;
  r->prot      = (bw[1] & 0x01) >> 0;
  r->layer     = (bw[1] & 0x06) >> 1;
  r->id        = (bw[1] & 0x08) >> 3;
  r->sync      = (bw[1] & 0xf0) >> 4;
  r->sync     |= (bw[0] & 0xff) << 4;
}

/* bitmasks for Xing flags */
#define XING_FRAMES     0x0001 
#define XING_BYTES      0x0002
#define XING_TOC        0x0004
#define XING_VBR_SCALE  0x0008

/* check if the frame with header h at startpos is an Xing VBR info frame
 * if yes, return 1 and calculate the length of the bitstream in seconds and
 * the average bitrate.
 * The Xing VBR info frame is "documented" in LAME's VbrTag.[ch] files.
 * It looks like a normal mp3 frame (it starts with a valid frame header)
 * but instead of containing bitstream data, it contains information on the
 * VBR bitsteam. It can be identified by the string "Xing" immediately
 * following the frame's side info. The next four bytes give flags identifying
 * what information is available in the frame. Usually, the info frame
 * provides the number of frames, the number of bytes in the bitstream
 * (excluding ID3 tags etc.), a 100-byte table of contents (TOC) array to
 * help an mp3 player seek within a VBR file, and a "VBR scale". We only care
 * about the first two items. */
int checkxing(int f, hdr_t h, int startpos, size_t sz1, 
	      int *seconds, int *avgbrate)
{
  unsigned char buf[16];
  unsigned char *p;
  int bpsi, n, spf;
  unsigned long flags, numframes, numbytes;
  
  /* determine number of bytes of side info + optional 16-bit CRC */
  if (h.id == 1)
    bpsi = (h.mode == 3) ? 17 : 32;
  else
    bpsi = (h.mode == 3) ? 9 : 17;
  if (h.prot == 0) /* 16-bit CRC follows frame header */
    bpsi += 2;
  
  /* skip header, CRC, and side info */
  lseek(f, startpos+4+bpsi, SEEK_SET); 
  n = read(f, buf, sizeof(buf));
  if (n < 16) {
    return 0;
  }
  if (strncmp(buf, "Xing", 4) != 0) {
    return 0;
  }
  /* this frame is an Xing info frame; next four bytes are the Xing flags */
  p = buf+4;
  flags = (unsigned long)p[0] << 24 | (unsigned long)p[1] << 16 | \
          (unsigned long)p[2] << 8  | (unsigned long)p[3];
  if (flags & XING_FRAMES) { /* next four bytes give number of frames */
    p = buf+8;
    numframes = (unsigned long)p[0] << 24 | (unsigned long)p[1] << 16 | \
                (unsigned long)p[2] << 8  | (unsigned long)p[3];
  } else {
    /* Xing frame doesn't even tell us how many frames there are! */
    return 0;
  }
  if (flags & XING_BYTES) {
    /* next 4 bytes give number of bytes in bitstream */
    p = buf+12;
    numbytes = (unsigned long)p[0] << 24 | (unsigned long)p[1] << 16 | \
               (unsigned long)p[2] << 8  | (unsigned long)p[3];
  } else {
    /* just use what we already know about the bitstream size */
    numbytes = sz1;
  }
  if ((numframes == 0) || (numbytes == 0)) { /* broken Xing frame? */
      return 0;
  }
  /* number of seconds = numframes * (seconds per frame) 
   * seconds per frame = (samples/frame)*(seconds/sample) = spf * (1/freq)
   * spf = 1152 (MPEG-1 Layer III) or 576 (MPEG-2 Layer III) (576*2=1152) */
  spf = (h.id) ? 1152 : 576;
  *seconds = numframes * spf / freqtab[h.id][h.freq];
  *avgbrate = numbytes * 8 / (*seconds * 1000);
  return 1;
}

/* check if two frame headers have same id, layer, prot, freq, mode fields */
int samestream(hdr_t a, hdr_t b) 
{
   if ((a.id == b.id) && (a.layer == b.layer) && (a.prot == b.prot) && 
       (a.freq == b.freq) && (a.mode == b.mode)) {
     return(1);
   }
   return(0);
}

/* The frame length is calculated as follows:
 * bpf = bytes per frame (including frame header)
 *     = bits/second * bytes/bit * samples/frame * seconds/sample
 *     = 1000 * kbps * 1/8 * spf * (1/freq)
 *     = kbps * 125 * spf * (1/freq)
 * spf = 1152 (MPEG-1 Layer III) or 576 (MPEG-2 Layer III) 
 *   
 * Note that freq doesn't evenly divide into kbps*spf*125 when freq is
 * 22050 or 44100. It seems that encoders deal with the remainder by adding
 * an extra byte to some of the frames and setting the pad bit in the frame
 * header. We must add one to bpf if a frame header's pad bit is 1.  */ 
int framesize(hdr_t h)
{
  int kbps, freq, bpf, spf;
  
  kbps = bratetab[h.id][h.brate];
  freq = freqtab[h.id][h.freq];
  spf = (h.id) ? 1152 : 576;
  bpf = (kbps * spf * 125 / freq) + h.pad;
  return(bpf);
}

/* return 1 if it looks like the file has a variable bitrate
 *   startpos is the position in file f where the mp3 stream starts, 
 *   size is the size of f in bytes
 * If there is no Xing VBR info frame, 
 * the only way to know for sure if a file is VBR is to read every single
 * frame header. This takes a relatively long time, so we use an approximate
 * method borrowed from Cedric Tefft's mp3info. The idea is to sample a few
 * frame headers throughout the file to see if they have the same bitrate as
 * the first header in the file. Although this works well in practice,
 * it is not fail-proof:
 * 1) some VBR files might not be recognized as VBR if the set of 
 *    headers sampled happen to have the same bitrate
 * 2) because we jump into the middle of the file and look for a frame header,
 *    it is possible that what looks like a frame header is actually frame
 *    data. If this false frame header happens to have a bitrate field that
 *    differs from that of the first header, a non-VBR file might be 
 *    incorrectly identified as VBR. As a result, the file will be unneccessarily
 *    fully scanned in mp3info. */
int checkvbr(int f, int startpos, int size, hdr_t firsthdr)
{
  int stepsize, i, j, isvbr, headerfound, bpf;
  unsigned char buf[4];
  hdr_t h, h2;

  isvbr = 0;
  stepsize = (size - startpos)/4;
  /* sample up to three headers throughout the file and compare the
   * header's bitrate to that of the first header */
  for (i = 1; i < 4; i++) {
    lseek(f, startpos + i*stepsize, SEEK_SET);
    headerfound = 0;
    /* get first four bytes at this position */
    if (read(f, buf, 4) < 4)
      break;  
    /* scan for frame header. Limit search to max frame size (1440 bytes) */
    for (j = 0; j < 1440; j++) { 
      buf4tohdr(buf, &h);
      if (checkhdr(&h) && samestream(firsthdr, h)) {
        /* id, layer, prot, freq, and mode match first header */
        /* if h is really a header, there should also be a header following
         * this frame */
        bpf = framesize(h);
        lseek(f, bpf-4, SEEK_CUR);
        if (read(f, buf, 4) < 4)
          break;
        buf4tohdr(buf, &h2);
        if (checkhdr(&h2) && samestream(firsthdr, h2)) {
          /* found two consecutive frame headers that match first header's
           * id, layer, prot, freq, and mode. h is probably a real header. */
          headerfound = 1;
          break;
        }
        /* h2 is not a valid header, so neither is h. Rewind. */
        lseek(f, -bpf, SEEK_CUR);
      }
      /* h is not a valid header; continue searching */
      buf[0] = buf[1];
      buf[1] = buf[2];
      buf[2] = buf[3];
      if (!read(f, &buf[3], 1)) 
        break; 
    } /* end for j */
    if (!headerfound) {
      /* there's something wrong (couldn't find a valid header)
       * but we pretend not to notice (act as if the file were CBR) */
      break; 
    }
    if (firsthdr.brate != h.brate) { /* bitrates differ */
      isvbr = 1;
      break;
    }
    /* bitrates matched, try a header in another section of the file */
  } /* end for */
  return(isvbr);
}

/* get the mp3 information (bitrate, frequency, length in seconds,
   size in bytes, and checksum) from the named mp3 file. */
mhdr_t *mp3info(char *fn)
{
  hdr_t m;
  mhdr_t *r;
  int f;
  size_t size = 0;
  struct stat st;
  id3v2_t tag;
  char rdt[3];
  size_t id3size, endtagsize;
  int numframes, bpf, spf;
  int seconds, avgbrate;
  hdr_t h;
  int res;

  f = open(fn, O_RDONLY);
  if (f == -1)
    return(NULL);
  
  /* first check whether there is an id3v2 header. Let id3size be its
     length. */
  id3size = 0;
  memset(rdt, 0, sizeof(rdt));
  read(f, &rdt, 3);
  if (!strncmp(rdt, "ID3", 3))  /* found id3v2 header */
  {
    lseek(f, 0, SEEK_SET);
    read(f, &tag, sizeof(tag));
    /* corrected a bug here: according to id3v2 spec, the size is
     * represented as a "synchsafe", or base-128, integer. 
     * This means 28 bits encode 32 bits as follows:
     *  0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx means
     *  0000xxxx xxxxxxxx xxxxxxxx xxxxxxxx.         -PS
     */
    size = (long)tag.size[0] << (24-3)|(long)tag.size[1] << (16-2)|(long)tag.size[2] << (8-1)|(long)tag.size[3];

    /* skip the id3v2 header */
    if (tag.flags & 0x10) {
      /* this is new in id3v2 version 4.0: tag.flags & 0x10 indicates
	 the presence of a "footer", which is 10 bytes in length, and which is
	 *not* included in the stored tag size */
      id3size = size+20;
    } else {
      id3size = size+10;
    }
  }

  /* next, check for the existence of a 128-byte tag at the end of the
     file. Let endtagsize be its length. */
  endtagsize = 0;
  lseek(f, -128, SEEK_END); 
  memset(rdt, 0, sizeof(rdt));
  read(f, &rdt, 3);
  if (!strncmp(rdt, "TAG", 3))  /* found end-tag */
    endtagsize = 128;
  
  /* first mp3 header should begin just after ID3 tag */
  lseek(f, id3size, SEEK_SET);
  if (!getrhdr(f, &m))
  {
    close(f);
    return(NULL);
  }
  
  fstat(f, &st);

  r = (mhdr_t *)malloc(sizeof(mhdr_t));
  memset(r, 0, sizeof(mhdr_t));
  
  /* sample frequency and size. Note: r->sz is the file size, whereas
     r->sz1 is the length of the mp3 stream (=file size minus any tags) */
  r->freq = freqtab[m.id][m.freq];
  r->sz = st.st_size;
  r->sz1 = r->sz - id3size - endtagsize;
  
  /* to set the song length and average bitrate, we must do different
     things depending on whether the file is VBR (variable bitrate) or
     not. */

  /* check if first frame is an Xing VBR info frame */
  if (checkxing(f, m, id3size, r->sz1, &seconds, &avgbrate)) {
    r->len = seconds;
    r->bitrate = avgbrate;
  } else if (checkvbr(f, id3size, st.st_size, m)) {
    /* Count the number of frames to determine the length in seconds.
     * number of seconds = numframes * (seconds per frame) 
     * seconds per frame = (samples/frame)*(seconds/sample) = spf * (1/freq)
     *   (seconds/frame is independent of bitrate)
     * spf = 1152 (MPEG-1 Layer III) or 576 (MPEG-2 Layer III) (576*2=1152)
     *   (samples/frame is independent of bitrate and frequency)
     * We have to read all the frame headers to determine the number of frames
     * because each frame can have a different bitrate and therefore a different
     * length.
     *
     * avg bitrate = (sum of bitrates over all frames)/numframes */
    lseek(f, id3size, SEEK_SET); 
    numframes = 0;
    while (getrhdr(f, &h)) {
      /* at this point we know m.brate < 15, m.freq < 3, and m.layer = 1 
       * all frames should have same frequency, layer, and id but we don't
       * check for this */
      numframes++;
      bpf = framesize(h);
      lseek(f, bpf-4, SEEK_CUR); /* seek to next frame header */
    } /* end while getrhdr */
    /* at this point we have reached EOF or an invalid header */
    if (numframes == 0) { /* no valid headers found */
      close(f);
      free(r);
      return(NULL);
    } 
    spf = (m.id) ? 1152 : 576;
    r->len = numframes * spf / r->freq;

    /* avg bitrate in kbps = (number of kilobits)/(number of seconds) */
    if (r->len == 0) {  /* patch #442669, jpavel */
      /* We have a problem here. */
      close(f);
      free(r);
      return(NULL);
    } 
    r->bitrate = (r->sz1/r->len)/125;

  } else {
    /* assume bitrate is constant */
    r->bitrate = bratetab[m.id][m.brate];
    r->len = (r->sz1/r->bitrate)/125;
  }

  /* finally, seek to end of ID3 header and calculate md5 hash */
  lseek(f, id3size, SEEK_SET);
  res = md5hash(r->check, f);
  if (res) {
    free(r);
    close(f);
    return(NULL);
  }

  close(f);
  return(r);
}

/* support for ogg vorbis files: get standard information (bitrate,
   frequency, length in seconds, size in bytes, and checksum) from the
   names ogg vorbis file. Return NULL if not recognized as a valid ogg
   vorbis file. */
mhdr_t *ogginfo(char *fn)
{
  /* note: since ogg uses variable bitrate, to keep things simple, we
     use the "nominal", rather than the "actual" bitrate of the ogg
     stream. This information can be read from the first header
     packet.  Otherwise we'd have to scan the entire file. We also
     only give a rough estimate of the song length, based on the file
     size. Sorry. Scanning an ogg vorbis file for that information
     would require ogg and vorbis parsers, which is too much overhead
     for us here. */

  /* we make some simple assumptions: the file contains an ogg stream
     revision 0, whose first page contains precisely one package,
     which is a vorbis "1" header. All other kinds of ogg streams will
     fail here. Information on ogg streams comes from
     http://www.xiph.org/ogg/vorbis/doc/framing.html, information on
     vorbis "1" header comes from vorbis/lib/info.c in the vorbis
     distribution. */

  unsigned char buf[0x58];
  int n;
  int f;
  mhdr_t *r;
  struct stat st;
  int res;

  /* get file stats and read first 58 bytes */
  f = open(fn, O_RDONLY);
  if (f == -1) {
    return NULL;goto fail;
  }
  fstat(f, &st);
  n = read(f, buf, 58);

  if (n<58) {
    goto fail;
  }
  
  /* check that this is a first page of a logical ogg stream. We don't
     bother checking the CRC checksum */
  if (strncmp(&buf[0], "OggS", 4) != 0) {        /* capture pattern */
    goto fail;
  }
  if (buf[4] != 0) {                             /* stream structure version */
    goto fail;
  }
  if ((buf[5] & 3) != 2) {                       /* ogg header type flag */
    goto fail;
  }
  if (buf[18] || buf[19] || buf[20] || buf[21]) {/* page sequence no. */
    goto fail;                                 
  }
  if (buf[26] != 1 || buf[27] != 30) {           /* segment table */
    goto fail;
  }

  /* check that this is a vorbis "1" header */
  if (buf[28] != 1) {                            /* vorbis packet type */
    goto fail;
  }
  if (strncmp(&buf[29], "vorbis", 6) != 0) {     /* vorbis packet identifier */
    goto fail;
  }
  if (buf[35] || buf[36] || buf[37] || buf[38]) {/* vorbis version */
    goto fail;                                 
  }
  if ((buf[57] & 1) != 1) {                      /* EOP check */
    goto fail;
  }
  
  /* seems we found an okay vorbis packet, now read the data. We
     ignore the "upper" and "lower" bitrates and go straight for the
     nominal bitrate. */

  r = (mhdr_t *)malloc(sizeof(mhdr_t));
  if (!r) {   
    goto fail;   /* out of memory; fail silently */
  }

  /* channels = buf[39]; */
  r->freq    = buf[40] | (buf[41]<<8) | (buf[42]<<16) | (buf[43]<<24);
  r->bitrate = buf[48] | (buf[49]<<8) | (buf[50]<<16) | (buf[51]<<24);
  r->sz      = st.st_size;
  r->sz1     = st.st_size;

  /* we have to estimate the length, based on bitrate and file size */
  if(!r->bitrate) {   /* bitrate was for some reason zero */
    free(r);
    goto fail;
  }
  r->len     = r->sz * 8 / r->bitrate;

  /* convert from bps to kbps */
  r->bitrate /= 1000;  

  /* calculate checksum */
  lseek(f, 0, SEEK_SET);
  res = md5hash(r->check, f);
  if (res) {
    free(r);
    goto fail;
  }

  close(f);
  return r;

 fail:
  close(f);
  return NULL;
}

/* calculate md5 hash of the given stream, starting from the current
   file position. md5bocks is the number of blocks to hash. Write to
   check. Return -1 on error, else 0. New in 1.5.1: if the user
   variable "hash" is not set, do not hash, but return a constant
   string instead. */

int md5hash(char check[33], int fd) {
  unsigned char md5[16];
  int i;

  if (nvar_default("hash", 0) == 0) {
    /* do not hash - return constant string */
    strcpy(check, BOGUS_HASH);
    return 0;
  }

  /* We hash the first 300032 bytes, not 300000 bytes as nap used to
     do. By the way, 300032 = 1024 * 293. -PS */

  if (md5_stream_blocks(fd, 293, md5)) {
    return(-1);
  }

  for (i=0;i<16;i++)
    sprintf(check+2*i, "%02x", md5[i]);
  
  /*  check[32] = '\0'; */
  
  return(0);
}

/* the next function really belongs in md5.c, but since that file is
   taken verbatim from GNU, we prefer not to change it. */

/* Compute MD5 message digest for 1024 * KB bytes read from file FD.
   The resulting message digest number will be written into the 16
   bytes beginning at RESBLOCK. Return 1 on error. */
int md5_stream_blocks (int fd, int kb, void *resblock)
{
  struct md5_ctx ctx;
  char buffer[1024 + 72];
  size_t sum;

  /* Initialize the computation context.  */
  md5_init_ctx (&ctx);

  /* Iterate over full file contents.  */
  while (kb>0)
    {
      /* We read the file in blocks of 1024 bytes.  One call of the
	 computation function processes the whole buffer so that with the
	 next round of the loop another block can be read.  */
      size_t n;
      sum = 0;

      /* Read block.  Take care for partial reads.  */
      do
	{
	  n = read (fd, buffer + sum, 1024 - sum);

	  sum += n;
	}
      while (sum < 1024 && n != 0 && n != -1);
      if (n == -1)
        return 1;

      /* If end of file is reached, end the loop.  */
      if (n == 0) {
	/* Add the last bytes if necessary.  */
	if (sum > 0)
	  md5_process_bytes (buffer, sum, &ctx);
	break;
      }
      
      /* Process buffer with 1024 bytes.  Note that 1024 % 64 == 0   */
      md5_process_block (buffer, 1024, &ctx);
      
      kb--;
    }

  /* Construct result in desired memory.  */
  md5_finish_ctx (&ctx, resblock);
  return 0;
}
