/* infcodes.c -- process literals and length/distance pairs
 * Copyright (C) 1995 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h 
 */

#include "zutil.h"
#include "inftrees.h"
#include "infutil.h"
#include "infcodes.h"

/* simplify the use of the inflate_huft type with some defines */
#define base more.Base
#define next more.Next
#define exop word.what.Exop
#define bits word.what.Bits

/* inflate codes private state */
struct inflate_codes_state {

  /* mode */
  enum {	/* waiting for "i:"=input, "o:"=output, "x:"=nothing */
      START,	/* x: set up for LEN */
      LEN,	/* i: get length/literal/eob next */
      LENEXT,	/* i: getting length extra (have base) */
      DIST,	/* i: get distance next */
      DISTEXT,	/* i: getting distance extra */
      COPY,	/* o: copying bytes in window, waiting for space */
      LIT,	/* o: got literal, waiting for output space */
      WASH,	/* o: got eob, possibly still output waiting */
      END,	/* x: got eob and all data flushed */
      BAD}	/* x: got error */
    mode;		/* current inflate_codes mode */

  /* mode dependent information */
  uInt len;
  union {
    struct {
      inflate_huft *tree;	/* pointer into tree */
      uInt need;		/* bits needed */
    } code;		/* if LEN or DIST, where in tree */
    uInt lit;		/* if LIT, literal */
    struct {
      uInt get;			/* bits to get for extra */
      uInt dist;		/* distance back to copy from */
    } copy;		/* if EXT or COPY, where and how much */
  } sub;		/* submode */

  /* mode independent information */
  Byte lbits;		/* ltree bits decoded per branch */
  Byte dbits;		/* dtree bits decoder per branch */
  inflate_huft *ltree;		/* literal/length/eob tree */
  inflate_huft *dtree;		/* distance tree */

};


struct inflate_codes_state *inflate_codes_new(bl, bd, tl, td, z)
uInt bl, bd;
inflate_huft *tl, *td;
z_stream *z;
{
  struct inflate_codes_state *c;

  if ((c = (struct inflate_codes_state *)
       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
  {
    c->mode = START;
    c->lbits = (Byte)bl;
    c->dbits = (Byte)bd;
    c->ltree = tl;
    c->dtree = td;
  }
  return c;
}


int inflate_codes(s, z, r)
struct inflate_blocks_state *s;
z_stream *z;
int r;
{
  uInt j;		/* temporary storage */
  inflate_huft *t;	/* temporary pointer */
  int e;		/* extra bits or operation */
  uLong b;		/* bit buffer */
  uInt k;		/* bits in bit buffer */
  Byte *p;		/* input data pointer */
  uInt n;		/* bytes available there */
  Byte *q;		/* output window write pointer */
  uInt m;		/* bytes to end of window or read pointer */
  Byte *f;		/* pointer to copy strings from */
  struct inflate_codes_state *c = s->sub.codes;	/* codes state */

  /* copy input/output information to locals (UPDATE macro restores) */
  LOAD

  /* process input and output based on current state */
  while (1) switch (c->mode)
  {		/* waiting for "i:"=input, "o:"=output, "x:"=nothing */
    case START:		/* x: set up for LEN */
      /* %%% check for avail in and out to do fast loop %%% */
      c->sub.code.need = c->lbits;
      c->sub.code.tree = c->ltree;
      c->mode = LEN;
    case LEN:		/* i: get length/literal/eob next */
      j = c->sub.code.need;
      NEEDBITS(j)
      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
      DUMPBITS(t->bits)
      if ((e = (int)(t->exop)) < 0)
      {
        if (e == -128)		/* invalid code */
	{
	  c->mode = BAD;
	  z->msg = "invalid huffman code";
	  r = Z_DATA_ERROR;
	  LEAVE
	}
	e = -e;
	if (e & 64)		/* end of block */
	{
	  c->mode = END;
	  break;
	}
	c->sub.code.need = e;
	c->sub.code.tree = t->next;
	break;
      }
      if (e & 16)		/* literal */
      {
	c->sub.lit = t->base;
	c->mode = LIT;
	break;
      }
      c->sub.copy.get = e;
      c->len = t->base;
      c->mode = LENEXT;
    case LENEXT:	/* i: getting length extra (have base) */
      j = c->sub.copy.get;
      NEEDBITS(j)
      c->len += (uInt)b & inflate_mask[j];
      DUMPBITS(j)
      c->sub.code.need = c->dbits;
      c->sub.code.tree = c->dtree;
      c->mode = DIST;
    case DIST:		/* i: get distance next */
      j = c->sub.code.need;
      NEEDBITS(j)
      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
      DUMPBITS(t->bits)
      if ((e = (int)(t->exop)) < 0)
      {
        if (e == -128)
	{
	  c->mode = BAD;
	  z->msg = "invalid huffman code";
	  r = Z_DATA_ERROR;
	  LEAVE
	}
	c->sub.code.need = -e;
	c->sub.code.tree = t->next;
	break;
      }
      c->sub.copy.dist = t->base;
      c->sub.copy.get = e;
      c->mode = DISTEXT;
    case DISTEXT:	/* i: getting distance extra */
      j = c->sub.copy.get;
      NEEDBITS(j)
      c->sub.copy.dist += (uInt)b & inflate_mask[j];
      DUMPBITS(j)
      c->mode = COPY;
    case COPY:		/* o: copying bytes in window, waiting for space */
      f = q - s->window < c->sub.copy.dist ?
	  s->end - (c->sub.copy.dist - (q - s->window)) :
	  q - c->sub.copy.dist;
      while (c->len)
      {
	NEEDOUT
	OUTBYTE(*f++)
	if (f == s->end)
	  f = s->window;
	c->len--;
      }
      c->mode = START;
      break;
    case LIT:		/* o: got literal, waiting for output space */
      NEEDOUT
      OUTBYTE(c->sub.lit)
      c->mode = START;
      break;
    case WASH:		/* o: got eob, possibly more output */
      FLUSH
      if (s->read != s->write)
        LEAVE
      c->mode = END;
    case END:
      r = Z_STREAM_END;
      LEAVE
    case BAD:		/* x: got error */
      r = Z_DATA_ERROR;
      LEAVE
    default:
      r = Z_STREAM_ERROR;
      LEAVE
  }
}


void inflate_codes_free(c, z)
struct inflate_codes_state *c;
z_stream *z;
{
  inflate_trees_free(c->dtree, z);
  inflate_trees_free(c->ltree, z);
  ZFREE(z, c);
}