_X_HIDDEN BufFilePtr
BufFilePushBZIP2 (BufFilePtr f)
{
    xzip_buf *x;

    x = malloc (sizeof (xzip_buf));
    if (!x) return NULL;

    bzero(&(x->z), sizeof(bz_stream));
    x->f = f;

    x->zstat = BZ2_bzDecompressInit(&(x->z),
				    0,	/* verbosity: 0 silent, 4 max */
				    0);	/* 0: go faster, 1: use less memory */
    if (x->zstat != BZ_OK) {
	free(x);
	return NULL;
    }

    /* now that the history buffer is allocated, we provide the data buffer */
    x->z.next_out = (char *) x->b;
    x->z.avail_out = BUFFILESIZE;
    x->z.next_in = (char *) x->b_in;
    x->z.avail_in = 0;

    return BufFileCreate((char *)x,
			 BufBzip2FileFill,
			 NULL,
			 BufBzip2FileSkip,
			 BufBzip2FileClose);
}
BufFilePtr
BufFilePushZIP (BufFilePtr f)
{
  xzip_buf *x;

  x = malloc (sizeof (xzip_buf));
  if (!x) return 0;
  /* these are just for raw calloc/free */
  x->z.zalloc = Z_NULL;
  x->z.zfree = Z_NULL;
  x->z.opaque = Z_NULL;
  x->f = f;

  /* force inflateInit to allocate it's own history buffer */
  x->z.next_in = Z_NULL;
  x->z.next_out = Z_NULL;
  x->z.avail_in = x->z.avail_out = 0;

  /* using negative windowBits sets "nowrap" mode, which turns off
     zlib header checking [undocumented, for gzip compatibility only?] */
  x->zstat = inflateInit2(&(x->z), -MAX_WBITS);
  if (x->zstat != Z_OK) {
    free(x);
    return 0;
  }

  /* now that the history buffer is allocated, we provide the data buffer */
  x->z.next_out = x->b;
  x->z.avail_out = BUFFILESIZE;
  x->z.next_out = x->b_in;
  x->z.avail_in = 0;

  if (BufCheckZipHeader(x->f)) {
    free(x);
    return 0;
  }

  return BufFileCreate((char *)x,
		       BufZipFileFill,
		       0,
		       BufZipFileSkip,
		       BufZipFileClose);
}