#include <stdio.h>
#include <string.h>
#include <malloc.h>

#include "libpgp5.h"

#define RBSIZ 10000
/* doesn't do nested signatures */
int dlitck5(FILE * inf, FILE * outf, int *sigret)
{
  unsigned char dbuf[RBSIZ], *sigbuf = NULL, *bp, xch = 0;
  unsigned int halg, i, k, ll = 0, neof = 0;
  void *hctx = NULL;

  /* skip2ctb5 (and checksig) */
  *sigret = 0;
  halg = 0;
  /* skip to literal */
  while (!feof(inf) && xch != 0xcb && (xch & 0xfc) != 0xac) {
    xch = fgetc(inf);
    if ((xch & 0xfc) == 0x88) {
      sigbuf = gazinta(inf, xch, NULL);
      halg = sigbuf[16];        /* grab algorithm */
    } else if (xch != 0xcb && (xch & 0xfc) != 0xac) {
      if (!(bp = gazinta(inf, xch, NULL)))
        return -3;
      if (xch == 0xc4)          /* one pass sig header */
        halg = bp[2];           /* grab algorithm */
      free(bp);
    }
  }
  if (xch != 0xcb && (xch & 0xfc) != 0xac)
    return -1;

  /* literal - get first length and bypass header */
  if (xch == 0xcb) {
    if ((ll = fgetc(inf)) >= 0xc0) {
      if (ll >= 0xe0)
        if (ll == 0xff)
          for (k = 0, ll = 0; k < 4; k++)
            ll = (ll << 8) + fgetc(inf);
        else
          ll = 1 << (ll & 31), neof = 1;  /* nonterminal chunk */
      else
        ll = ((ll & 31) << 8) + 192 + fgetc(inf);
    }
  } else {
    i = 1 << (xch & 3);         /* length of length */
    for (k = 0, ll = 0; k < i; k++)
      ll = (ll << 8) + fgetc(inf);
  }
  /* PROBLEMS IF HEADER FRAGMENTED */
  if (ll < 6)
    return -5;
  fgetc(inf);                   /* type */
  xch = fgetc(inf);             /* len of fname */
  if (ll < xch + 6)
    return -5;
  ll -= xch + 6;
  fread(dbuf, 1, xch, inf);     /* SUGGESTED FILENAME */
  fread(dbuf, 1, 4, inf);       /* unused timestamp */

  *sigret = halg;
  /* pass through and optionally hash */
  if (halg)
    hctx = hashinit(halg);

  while (ll) {
    i = ll > RBSIZ ? RBSIZ : ll;
    k = fread(dbuf, 1, i, inf);
    ll -= k;
    fwrite(dbuf, 1, k, outf);

    if (halg)
      hashupdate(hctx, dbuf, k);

    if (!ll && neof--) {
      if ((ll = fgetc(inf)) >= 0xc0) {
        if (ll >= 0xe0) {
          if (ll >= 0xff)
            return -2;
          else
            neof = 1, ll = 1 << (ll & 31);  /* noteof */
        } else
          ll = ((ll & 31) << 8) + 192 + fgetc(inf);
      }
    }
  }

  if (!halg)
    return 0;

  if (!sigbuf) {
    i = fgetc(inf);
    if ((i & 0xfc) != 0x88 && i != 0xc2)
      return -1;
    sigbuf = gazinta(inf, i, NULL);
  }
  k = sigchk5(sigbuf, hctx);
  free(sigbuf);
  return k;
}
