view src/vtx/lh5dec.c @ 2284:d19b53359b24

cleaned up the sndfile wav plugin, currently limiting it ONLY TO WAV PLAYBACK. if somebody is more experienced with it and wants to restore the other formats, go ahead (maybe change the name of the plugin too?).
author mf0102 <0102@gmx.at>
date Wed, 09 Jan 2008 15:41:22 +0100
parents 33ffac81f4c7
children
line wrap: on
line source

/* extractiong lh5 module
   (c) Haruhiko Okumura
   (m) Roman Scherbakov
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>   /* memmove */
#include <limits.h>

static unsigned short bitbuf;

#define BITBUFSIZ (CHAR_BIT * sizeof bitbuf)

#define DICBIT    13    /* 12(-lh4-) or 13(-lh5-) */
#define DICSIZ   (1L << DICBIT)
#define MATCHBIT   8    /* bits for MAXMATCH - THRESHOLD */
#define MAXMATCH 256    /* formerly F (not more than unsigned char_MAX + 1) */
#define THRESHOLD  3    /* choose optimal value */
#define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
#define CBIT 9          /* $\lfloor \log_2 NC \rfloor + 1$ */
#define CODE_BIT  16    /* codeword length */
#define NP (DICBIT + 1)
#define NT (CODE_BIT + 3)
#define PBIT 4          /* smallest integer such that (1U << PBIT) > NP */
#define TBIT 5          /* smallest integer such that (1U << TBIT) > NT */
#if NT > NP
#define NPT NT
#else
#define NPT NP
#endif

static unsigned long origsize, compsize;
static unsigned char *in_buf;
static unsigned char *out_buf;

static unsigned short  subbitbuf;
static int   bitcount;

static unsigned short left[2 * NC - 1], right[2 * NC - 1];
static unsigned char  c_len[NC], pt_len[NPT];
static unsigned short   blocksize;

static unsigned short c_table[4096], pt_table[256];

static int j;  /* remaining bytes to copy */


static void error(char *msg)
{
  fprintf(stderr, "libayemu: lh5dec.c: %s\n", msg);
  exit(EXIT_FAILURE);
}

static void fillbuf(int n)  /* Shift bitbuf n bits left, read n bits */
{
  bitbuf <<= n;
  while (n > bitcount) {
    bitbuf |= subbitbuf << (n -= bitcount);
    if (compsize != 0) {
      compsize--;  subbitbuf = *in_buf++;
    } else subbitbuf = 0;
    bitcount = CHAR_BIT;
  }
  bitbuf |= subbitbuf >> (bitcount -= n);
}

static unsigned short getbits(int n)
{
  unsigned short x;

  x = bitbuf >> (BITBUFSIZ - n);  fillbuf(n);
  return x;
}

// make table for decoding

static void make_table(int nchar, unsigned char bitlen[], int tablebits, unsigned short table[])
{
  unsigned short count[17], weight[17], start[18], *p;
  unsigned short i, k, len, ch, jutbits, avail, nextcode, mask;

  for (i = 1; i <= 16; i++) count[i] = 0;
  for (i = 0; i < nchar; i++) count[bitlen[i]]++;

  start[1] = 0;
  for (i = 1; i <= 16; i++)
    start[i + 1] = start[i] + (count[i] << (16 - i));
  if (start[17] != (unsigned short)(1U << 16)) error("Bad table");

  jutbits = 16 - tablebits;
  for (i = 1; i <= tablebits; i++) {
    start[i] >>= jutbits;
    weight[i] = 1U << (tablebits - i);
  }
  while (i <= 16) {
      weight[i] = 1U << (16 - i);
      i++;
  }

  i = start[tablebits + 1] >> jutbits;
  if (i != (unsigned short)(1U << 16)) {
    k = 1U << tablebits;
    while (i != k) table[i++] = 0;
  }

  avail = nchar;
  mask = 1U << (15 - tablebits);
  for (ch = 0; ch < nchar; ch++) {
    if ((len = bitlen[ch]) == 0) continue;
    nextcode = start[len] + weight[len];
    if (len <= tablebits) {
      for (i = start[len]; i < nextcode; i++) table[i] = ch;
    } else {
      k = start[len];
      p = &table[k >> jutbits];
      i = len - tablebits;
      while (i != 0) {
	if (*p == 0) {
	  right[avail] = left[avail] = 0;
	  *p = avail++;
	}
	if (k & mask) p = &right[*p];
	else          p = &left[*p];
	k <<= 1;  i--;
      }
      *p = ch;
    }
    start[len] = nextcode;
  }
}

// static Huffman

static void read_pt_len(int nn, int nbit, int i_special)
{
  int i, c, n;
  unsigned short mask;

  n = getbits(nbit);
  if (n == 0) {
    c = getbits(nbit);
    for (i = 0; i < nn; i++) pt_len[i] = 0;
    for (i = 0; i < 256; i++) pt_table[i] = c;
  } else {
    i = 0;
    while (i < n) {
      c = bitbuf >> (BITBUFSIZ - 3);
      if (c == 7) {
	mask = 1U << (BITBUFSIZ - 1 - 3);
	while (mask & bitbuf) {  mask >>= 1;  c++;  }
      }
      fillbuf((c < 7) ? 3 : c - 3);
      pt_len[i++] = c;
      if (i == i_special) {
	c = getbits(2);
	while (--c >= 0) pt_len[i++] = 0;
      }
    }
    while (i < nn) pt_len[i++] = 0;
    make_table(nn, pt_len, 8, pt_table);
  }
}

static void read_c_len(void)
{
  int i, c, n;
  unsigned short mask;

  n = getbits(CBIT);
  if (n == 0) {
    c = getbits(CBIT);
    for (i = 0; i < NC; i++) c_len[i] = 0;
    for (i = 0; i < 4096; i++) c_table[i] = c;
  } else {
    i = 0;
    while (i < n) {
      c = pt_table[bitbuf >> (BITBUFSIZ - 8)];
      if (c >= NT) {
	mask = 1U << (BITBUFSIZ - 1 - 8);
	do {
	  if (bitbuf & mask) c = right[c];
	  else               c = left [c];
	  mask >>= 1;
	} while (c >= NT);
      }
      fillbuf(pt_len[c]);
      if (c <= 2) {
	if      (c == 0) c = 1;
	else if (c == 1) c = getbits(4) + 3;
	else             c = getbits(CBIT) + 20;
	while (--c >= 0) c_len[i++] = 0;
      } else c_len[i++] = c - 2;
    }
    while (i < NC) c_len[i++] = 0;
    make_table(NC, c_len, 12, c_table);
  }
}


static unsigned short decode_c(void)
{
  unsigned short j, mask;

  if (blocksize == 0) {
    blocksize = getbits(16);
    read_pt_len(NT, TBIT, 3);
    read_c_len();
    read_pt_len(NP, PBIT, -1);
  }
  blocksize--;
  j = c_table[bitbuf >> (BITBUFSIZ - 12)];
  if (j >= NC) {
    mask = 1U << (BITBUFSIZ - 1 - 12);
    do {
      if (bitbuf & mask) j = right[j];
      else               j = left [j];
      mask >>= 1;
    } while (j >= NC);
  }
  fillbuf(c_len[j]);
  return j;
}


static unsigned short decode_p(void)
{
  unsigned short j, mask;

  j = pt_table[bitbuf >> (BITBUFSIZ - 8)];
  if (j >= NP) {
    mask = 1U << (BITBUFSIZ - 1 - 8);
    do {
      if (bitbuf & mask) j = right[j];
      else               j = left [j];
      mask >>= 1;
    } while (j >= NP);
  }
  fillbuf(pt_len[j]);
  if (j != 0) j = (1U << (j - 1)) + getbits(j - 1);
  return j;
}


static void decode(unsigned short count, unsigned char buffer[])
{
  static unsigned short i;
  unsigned short r, c;

  r = 0;
  while (--j >= 0) {
    buffer[r] = buffer[i];
    i = (i + 1) & (DICSIZ - 1);
    if (++r == count) return;
  }
  for ( ; ; ) {
    c = decode_c();
    if (c <= UCHAR_MAX) {
      buffer[r] = c & UCHAR_MAX;
      if (++r == count) return;
    } else {
      j = c - (UCHAR_MAX + 1 - THRESHOLD);
      i = (r - decode_p() - 1) & (DICSIZ - 1);
      while (--j >= 0) {
	buffer[r] = buffer[i];
	i = (i + 1) & (DICSIZ - 1);
	if (++r == count) return;
      }
    }
  }
}

void lh5_decode(unsigned char *inp, unsigned char *outp, unsigned long original_size, unsigned long packed_size)
{
  unsigned short n;
  unsigned char *buffer;

  compsize = packed_size;
  origsize = original_size;
  in_buf = inp;
  out_buf = outp;

  buffer = (unsigned char *) malloc(DICSIZ);
  if (!buffer) error ("Out of memory");

  bitbuf = 0;  subbitbuf = 0;  bitcount = 0;
  fillbuf(BITBUFSIZ);
  blocksize = 0;
  j = 0;

  while (origsize != 0) {
    n = (origsize > DICSIZ) ? DICSIZ : (unsigned short)origsize;
    decode(n, buffer);
    memmove(out_buf, buffer, n);
    out_buf += n;
    origsize -= n;
  }

  if (buffer) free (buffer);
  buffer = NULL;
}