798 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			798 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*  $Id$
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Part of SWI-Prolog
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Author:        Jan Wielemaker
							 | 
						||
| 
								 | 
							
								    E-mail:        wielemak@science.uva.nl
							 | 
						||
| 
								 | 
							
								    WWW:           http://www.swi-prolog.org
							 | 
						||
| 
								 | 
							
								    Copyright (C): 2006, University of Amsterdam
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This library is free software; you can redistribute it and/or
							 | 
						||
| 
								 | 
							
								    modify it under the terms of the GNU Lesser General Public
							 | 
						||
| 
								 | 
							
								    License as published by the Free Software Foundation; either
							 | 
						||
| 
								 | 
							
								    version 2.1 of the License, or (at your option) any later version.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This library is distributed in the hope that it will be useful,
							 | 
						||
| 
								 | 
							
								    but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						||
| 
								 | 
							
								    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
							 | 
						||
| 
								 | 
							
								    Lesser General Public License for more details.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    You should have received a copy of the GNU Lesser General Public
							 | 
						||
| 
								 | 
							
								    License along with this library; if not, write to the Free Software
							 | 
						||
| 
								 | 
							
								    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define O_DEBUG 1
							 | 
						||
| 
								 | 
							
								#include <SWI-Stream.h>
							 | 
						||
| 
								 | 
							
								#include <SWI-Prolog.h>
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <string.h>
							 | 
						||
| 
								 | 
							
								#include <assert.h>
							 | 
						||
| 
								 | 
							
								#include <time.h>
							 | 
						||
| 
								 | 
							
								#include <zlib.h>
							 | 
						||
| 
								 | 
							
								/* Some distributions do not include this ... */
							 | 
						||
| 
								 | 
							
								#ifdef HAVE_ZUTIL_H
							 | 
						||
| 
								 | 
							
								#include <zutil.h>
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#include "zutil.h"
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static functor_t FUNCTOR_error2;	/* error(Formal, Context) */
							 | 
						||
| 
								 | 
							
								static functor_t FUNCTOR_type_error2;	/* type_error(Term, Expected) */
							 | 
						||
| 
								 | 
							
								static functor_t FUNCTOR_domain_error2;	/* domain_error(Term, Expected) */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static atom_t ATOM_format;		/* format(Format) */
							 | 
						||
| 
								 | 
							
								static atom_t ATOM_level;		/* level(Int) */
							 | 
						||
| 
								 | 
							
								static atom_t ATOM_close_parent;	/* close_parent(Bool) */
							 | 
						||
| 
								 | 
							
								static atom_t ATOM_gzip;
							 | 
						||
| 
								 | 
							
								static atom_t ATOM_deflate;
							 | 
						||
| 
								 | 
							
								static int debuglevel = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef O_DEBUG
							 | 
						||
| 
								 | 
							
								#define DEBUG(n, g) if ( debuglevel >= n ) g
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#define DEBUG(n, g) (void)0
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	       ERRORS		*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								type_error(term_t actual, const char *expected)
							 | 
						||
| 
								 | 
							
								{ term_t ex;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( (ex = PL_new_term_ref()) &&
							 | 
						||
| 
								 | 
							
								       PL_unify_term(ex,
							 | 
						||
| 
								 | 
							
										     PL_FUNCTOR, FUNCTOR_error2,
							 | 
						||
| 
								 | 
							
										       PL_FUNCTOR, FUNCTOR_type_error2,
							 | 
						||
| 
								 | 
							
										         PL_CHARS, expected,
							 | 
						||
| 
								 | 
							
										         PL_TERM, actual,
							 | 
						||
| 
								 | 
							
										       PL_VARIABLE) )
							 | 
						||
| 
								 | 
							
								    return PL_raise_exception(ex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return FALSE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								domain_error(term_t actual, const char *domain)
							 | 
						||
| 
								 | 
							
								{ term_t ex;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( (ex = PL_new_term_ref()) &&
							 | 
						||
| 
								 | 
							
								       PL_unify_term(ex,
							 | 
						||
| 
								 | 
							
										     PL_FUNCTOR, FUNCTOR_error2,
							 | 
						||
| 
								 | 
							
										       PL_FUNCTOR, FUNCTOR_domain_error2,
							 | 
						||
| 
								 | 
							
										         PL_CHARS, domain,
							 | 
						||
| 
								 | 
							
										         PL_TERM, actual,
							 | 
						||
| 
								 | 
							
										       PL_VARIABLE) )
							 | 
						||
| 
								 | 
							
								  return PL_raise_exception(ex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return FALSE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								instantiation_error()
							 | 
						||
| 
								 | 
							
								{ term_t ex;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( (ex = PL_new_term_ref()) &&
							 | 
						||
| 
								 | 
							
								       PL_unify_term(ex,
							 | 
						||
| 
								 | 
							
										     PL_FUNCTOR, FUNCTOR_error2,
							 | 
						||
| 
								 | 
							
										       PL_CHARS, "instantiation_error",
							 | 
						||
| 
								 | 
							
										       PL_VARIABLE) )
							 | 
						||
| 
								 | 
							
								    return PL_raise_exception(ex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return FALSE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								get_atom_ex(term_t t, atom_t *a)
							 | 
						||
| 
								 | 
							
								{ if ( PL_get_atom(t, a) )
							 | 
						||
| 
								 | 
							
								    return TRUE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return type_error(t, "atom");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								get_int_ex(term_t t, int *i)
							 | 
						||
| 
								 | 
							
								{ if ( PL_get_integer(t, i) )
							 | 
						||
| 
								 | 
							
								    return TRUE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return type_error(t, "integer");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								get_bool_ex(term_t t, int *i)
							 | 
						||
| 
								 | 
							
								{ if ( PL_get_bool(t, i) )
							 | 
						||
| 
								 | 
							
								    return TRUE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return type_error(t, "boolean");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	       TYPES		*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define BUFSIZE SIO_BUFSIZE		/* raw I/O buffer */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef enum
							 | 
						||
| 
								 | 
							
								{ F_UNKNOWN = 0,
							 | 
						||
| 
								 | 
							
								  F_GZIP,				/* gzip output */
							 | 
						||
| 
								 | 
							
								  F_GZIP_CRC,				/* end of gzip output */
							 | 
						||
| 
								 | 
							
								  F_DEFLATE				/* zlib data */
							 | 
						||
| 
								 | 
							
								} zformat;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef struct z_context
							 | 
						||
| 
								 | 
							
								{ IOSTREAM	   *stream;		/* Original stream */
							 | 
						||
| 
								 | 
							
								  IOSTREAM	   *zstream;		/* Compressed stream (I'm handle of) */
							 | 
						||
| 
								 | 
							
								  int		    close_parent;	/* close parent on close */
							 | 
						||
| 
								 | 
							
								  int		    initialized;	/* did inflateInit()? */
							 | 
						||
| 
								 | 
							
								  zformat	    format;		/* current format */
							 | 
						||
| 
								 | 
							
								  uLong		    crc;		/* CRC check */
							 | 
						||
| 
								 | 
							
								  z_stream	    zstate;		/* Zlib state */
							 | 
						||
| 
								 | 
							
								} z_context;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static z_context*
							 | 
						||
| 
								 | 
							
								alloc_zcontext(IOSTREAM *s)
							 | 
						||
| 
								 | 
							
								{ z_context *ctx = PL_malloc(sizeof(*ctx));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  memset(ctx, 0, sizeof(*ctx));
							 | 
						||
| 
								 | 
							
								  ctx->stream       = s;
							 | 
						||
| 
								 | 
							
								  ctx->close_parent = TRUE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return ctx;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								free_zcontext(z_context *ctx)
							 | 
						||
| 
								 | 
							
								{ if ( ctx->stream->upstream )
							 | 
						||
| 
								 | 
							
								    Sset_filter(ctx->stream, NULL);
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    PL_release_stream(ctx->stream);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  PL_free(ctx);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	     GZIP HEADER	*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
							 | 
						||
| 
								 | 
							
								Code based on gzio.c from the zlib source distribution.
							 | 
						||
| 
								 | 
							
								- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* gzip flag byte */
							 | 
						||
| 
								 | 
							
								#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
							 | 
						||
| 
								 | 
							
								#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
							 | 
						||
| 
								 | 
							
								#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
							 | 
						||
| 
								 | 
							
								#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
							 | 
						||
| 
								 | 
							
								#define COMMENT      0x10 /* bit 4 set: file comment present */
							 | 
						||
| 
								 | 
							
								#define RESERVED     0xE0 /* bits 5..7: reserved */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
							 | 
						||
| 
								 | 
							
								gz_skip_header() parses the gzip file-header.  return
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									* If ok: pointer to first byte following header
							 | 
						||
| 
								 | 
							
									* If not a gzip file: NULL
							 | 
						||
| 
								 | 
							
									* If still ok, but incomplete: GZHDR_SHORT
							 | 
						||
| 
								 | 
							
								- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define HDR_SHORT ((Bytef*)-1)		/* Header is incomplete */
							 | 
						||
| 
								 | 
							
								#define SKIP_STRING \
							 | 
						||
| 
								 | 
							
									{ while ( *in && avail > 0 ) \
							 | 
						||
| 
								 | 
							
									    in++, avail--; \
							 | 
						||
| 
								 | 
							
									  if ( avail > 0 ) \
							 | 
						||
| 
								 | 
							
									    in++, avail--; \
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static Bytef *
							 | 
						||
| 
								 | 
							
								gz_skip_header(z_context *ctx, Bytef *in, int avail)
							 | 
						||
| 
								 | 
							
								{ int method; /* method byte */
							 | 
						||
| 
								 | 
							
								  int flags;  /* flags byte */
							 | 
						||
| 
								 | 
							
								  int len;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( avail < 10 )			/* 2-byte magic, method, flags, */
							 | 
						||
| 
								 | 
							
								    return HDR_SHORT;			/* time, xflags and OS code */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( in[0] != gz_magic[0] &&
							 | 
						||
| 
								 | 
							
								       in[1] != gz_magic[1] )
							 | 
						||
| 
								 | 
							
								    return NULL;
							 | 
						||
| 
								 | 
							
								  in += 2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  method = *in++;
							 | 
						||
| 
								 | 
							
								  flags  = *in++;
							 | 
						||
| 
								 | 
							
								  if ( method != Z_DEFLATED || (flags & RESERVED ) != 0)
							 | 
						||
| 
								 | 
							
								    return NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  in += 6;				/* Discard time, xflags and OS code */
							 | 
						||
| 
								 | 
							
								  avail -= 10;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ((flags & EXTRA_FIELD) != 0)
							 | 
						||
| 
								 | 
							
								  { /* skip the extra field */
							 | 
						||
| 
								 | 
							
								    len  =  *in++;
							 | 
						||
| 
								 | 
							
								    len += (*in++)<<8;
							 | 
						||
| 
								 | 
							
								    len &= 0xffff;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ( avail > len )
							 | 
						||
| 
								 | 
							
								    { in += len;
							 | 
						||
| 
								 | 
							
								      avail -= len;
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								    { return HDR_SHORT;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if ((flags & ORIG_NAME) != 0)
							 | 
						||
| 
								 | 
							
								  { /* skip the original file name */
							 | 
						||
| 
								 | 
							
								    SKIP_STRING
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if ((flags & COMMENT) != 0)
							 | 
						||
| 
								 | 
							
								  {   /* skip the .gz file comment */
							 | 
						||
| 
								 | 
							
								    SKIP_STRING
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if ((flags & HEAD_CRC) != 0)
							 | 
						||
| 
								 | 
							
								  {  /* skip the header crc */
							 | 
						||
| 
								 | 
							
								    in += 2;
							 | 
						||
| 
								 | 
							
								    avail -= 2;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( avail <= 0 )
							 | 
						||
| 
								 | 
							
								    return HDR_SHORT;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return in;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								write_ulong_lsb(IOSTREAM *s, unsigned long x)
							 | 
						||
| 
								 | 
							
								{ Sputc((x)    &0xff, s);
							 | 
						||
| 
								 | 
							
								  Sputc((x>>8) &0xff, s);
							 | 
						||
| 
								 | 
							
								  Sputc((x>>16)&0xff, s);
							 | 
						||
| 
								 | 
							
								  Sputc((x>>24)&0xff, s);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return Sferror(s) ? -1 : 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								write_gzip_header(z_context *ctx)
							 | 
						||
| 
								 | 
							
								{ IOSTREAM *s = ctx->stream;
							 | 
						||
| 
								 | 
							
								  time_t stamp = time(NULL);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  Sputc(gz_magic[0], s);
							 | 
						||
| 
								 | 
							
								  Sputc(gz_magic[1], s);
							 | 
						||
| 
								 | 
							
								  Sputc(Z_DEFLATED, s);			/* method */
							 | 
						||
| 
								 | 
							
								  Sputc(0, s);				/* flags */
							 | 
						||
| 
								 | 
							
								  write_ulong_lsb(s, (unsigned long)stamp); /* time stamp */
							 | 
						||
| 
								 | 
							
								  Sputc(0, s);				/* xflags */
							 | 
						||
| 
								 | 
							
								  Sputc(OS_CODE, s);			/* OS identifier */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return Sferror(s) ? FALSE : TRUE;	/* TBD: Error */
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								write_gzip_footer(z_context *ctx)
							 | 
						||
| 
								 | 
							
								{ IOSTREAM *s = ctx->stream;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  write_ulong_lsb(s, ctx->crc);		/* CRC32 */
							 | 
						||
| 
								 | 
							
								  write_ulong_lsb(s, ctx->zstate.total_in);	/* Total length */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return Sferror(s) ? -1 : 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static Bytef *
							 | 
						||
| 
								 | 
							
								get_ulong_lsb(const Bytef *in, uLong *v)
							 | 
						||
| 
								 | 
							
								{ *v = (in[0] |
							 | 
						||
| 
								 | 
							
									in[1] << 8 |
							 | 
						||
| 
								 | 
							
									in[2] << 16 |
							 | 
						||
| 
								 | 
							
									in[3] << 24) & 0xffffffff;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return (Bytef*)in+4;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
							 | 
						||
| 
								 | 
							
									0: ok
							 | 
						||
| 
								 | 
							
								       -1: CRC/size error
							 | 
						||
| 
								 | 
							
								       -2: not enough data
							 | 
						||
| 
								 | 
							
								- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								gz_skip_footer(z_context *ctx)
							 | 
						||
| 
								 | 
							
								{ if ( ctx->zstate.avail_in >= 8 )
							 | 
						||
| 
								 | 
							
								  { uLong crc, size;
							 | 
						||
| 
								 | 
							
								    Bytef *in = ctx->zstate.next_in;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    in = get_ulong_lsb(in, &crc);
							 | 
						||
| 
								 | 
							
								    in = get_ulong_lsb(in, &size);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ctx->zstate.next_in = in;
							 | 
						||
| 
								 | 
							
								    ctx->zstate.avail_in -= 8;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ( crc != ctx->crc )
							 | 
						||
| 
								 | 
							
								    { char msg[256];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      Ssprintf(msg, "CRC error (%08lx != %08lx)", crc, ctx->crc);
							 | 
						||
| 
								 | 
							
								      Sseterr(ctx->zstream, SIO_FERR, msg);
							 | 
						||
| 
								 | 
							
								      return -1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if ( size != ctx->zstate.total_out )
							 | 
						||
| 
								 | 
							
								    { char msg[256];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      Ssprintf(msg, "Size mismatch (%ld != %ld)", size, ctx->zstate.total_out);
							 | 
						||
| 
								 | 
							
								      Sseterr(ctx->zstream, SIO_FERR, msg);
							 | 
						||
| 
								 | 
							
								      return -1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return -2;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	       GZ I/O		*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
							 | 
						||
| 
								 | 
							
								read_more() reads more data into the   zstate buffer if deflating cannot
							 | 
						||
| 
								 | 
							
								do anything with the available  bytes.   Note  that  S__fillbuf() can be
							 | 
						||
| 
								 | 
							
								called with data in the buffer. It moves the remaining data to the start
							 | 
						||
| 
								 | 
							
								of the stream buffer and tries to read more data into the stream.
							 | 
						||
| 
								 | 
							
								- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								read_more(z_context *ctx)
							 | 
						||
| 
								 | 
							
								{ int c;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ctx->stream->bufp   = (char*)ctx->zstate.next_in;
							 | 
						||
| 
								 | 
							
								  ctx->stream->limitp =	ctx->stream->bufp + ctx->zstate.avail_in;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( (c=S__fillbuf(ctx->stream)) != EOF )
							 | 
						||
| 
								 | 
							
								  { Sungetc(c, ctx->stream);
							 | 
						||
| 
								 | 
							
								    ctx->zstate.next_in  = (Bytef*)ctx->stream->bufp;
							 | 
						||
| 
								 | 
							
								    ctx->zstate.avail_in = (long)(ctx->stream->limitp - ctx->stream->bufp);
							 | 
						||
| 
								 | 
							
								    ctx->stream->bufp    = ctx->stream->limitp;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return -1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static ssize_t				/* inflate */
							 | 
						||
| 
								 | 
							
								zread(void *handle, char *buf, size_t size)
							 | 
						||
| 
								 | 
							
								{ z_context *ctx = handle;
							 | 
						||
| 
								 | 
							
								  int flush = Z_SYNC_FLUSH;
							 | 
						||
| 
								 | 
							
								  int rc;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( ctx->zstate.avail_in == 0 )
							 | 
						||
| 
								 | 
							
								  { if ( Sfeof(ctx->stream) )
							 | 
						||
| 
								 | 
							
								    { flush = Z_FINISH;
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								    { ctx->zstate.next_in  = (Bytef*)ctx->stream->bufp;
							 | 
						||
| 
								 | 
							
								      ctx->zstate.avail_in = (long)(ctx->stream->limitp - ctx->stream->bufp);
							 | 
						||
| 
								 | 
							
								      ctx->stream->bufp    = ctx->stream->limitp; /* empty buffer */
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  DEBUG(1, Sdprintf("Processing %d bytes\n", ctx->zstate.avail_in));
							 | 
						||
| 
								 | 
							
								  ctx->zstate.next_out  = (Bytef*)buf;
							 | 
						||
| 
								 | 
							
								  ctx->zstate.avail_out = (long)size;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( ctx->initialized == FALSE )
							 | 
						||
| 
								 | 
							
								  { Bytef *p;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    DEBUG(1, Sdprintf("Trying gzip header\n"));
							 | 
						||
| 
								 | 
							
								    if ( ctx->format == F_DEFLATE )
							 | 
						||
| 
								 | 
							
								    { p = NULL;
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								    { while( (p = gz_skip_header(ctx, ctx->zstate.next_in,
							 | 
						||
| 
								 | 
							
												 ctx->zstate.avail_in)) == HDR_SHORT )
							 | 
						||
| 
								 | 
							
								      { int rc;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if ( (rc=read_more(ctx)) < 0 )
							 | 
						||
| 
								 | 
							
									  return -1;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ( p )
							 | 
						||
| 
								 | 
							
								    { long m = (int)(p - ctx->zstate.next_in);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      ctx->format = F_GZIP;
							 | 
						||
| 
								 | 
							
								      DEBUG(1, Sdprintf("Skipped gzip header (%d bytes)\n", m));
							 | 
						||
| 
								 | 
							
								      ctx->zstate.next_in = p;
							 | 
						||
| 
								 | 
							
								      ctx->zstate.avail_in -= m;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													/* init without header */
							 | 
						||
| 
								 | 
							
								      switch(inflateInit2(&ctx->zstate, -MAX_WBITS))
							 | 
						||
| 
								 | 
							
								      { case Z_OK:
							 | 
						||
| 
								 | 
							
									  ctx->initialized = TRUE;
							 | 
						||
| 
								 | 
							
									  ctx->crc = crc32(0L, Z_NULL, 0);
							 | 
						||
| 
								 | 
							
									  DEBUG(1, Sdprintf("inflateInit2(): Z_OK\n"));
							 | 
						||
| 
								 | 
							
									  break;
							 | 
						||
| 
								 | 
							
									case Z_MEM_ERROR:		/* no memory */
							 | 
						||
| 
								 | 
							
								        case Z_VERSION_ERROR:		/* bad library version */
							 | 
						||
| 
								 | 
							
									  PL_warning("ERROR: TBD");
							 | 
						||
| 
								 | 
							
									  return -1;
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
									  assert(0);
							 | 
						||
| 
								 | 
							
									  return -1;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								    { switch(inflateInit(&ctx->zstate))
							 | 
						||
| 
								 | 
							
								      { case Z_OK:
							 | 
						||
| 
								 | 
							
									  ctx->format = F_DEFLATE;
							 | 
						||
| 
								 | 
							
									  ctx->initialized = TRUE;
							 | 
						||
| 
								 | 
							
									  DEBUG(1, Sdprintf("inflateInit(): Z_OK\n"));
							 | 
						||
| 
								 | 
							
									  break;
							 | 
						||
| 
								 | 
							
									case Z_MEM_ERROR:		/* no memory */
							 | 
						||
| 
								 | 
							
								        case Z_VERSION_ERROR:		/* bad library version */
							 | 
						||
| 
								 | 
							
									  PL_warning("ERROR: TBD");
							 | 
						||
| 
								 | 
							
									  return -1;
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
									  assert(0);
							 | 
						||
| 
								 | 
							
									  return -1;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  } else if ( ctx->format == F_GZIP_CRC )
							 | 
						||
| 
								 | 
							
								  { int rc;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    while( (rc=gz_skip_footer(ctx)) == -2 )
							 | 
						||
| 
								 | 
							
								    { int rc2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if ( (rc2=read_more(ctx)) < 0 )
							 | 
						||
| 
								 | 
							
									return -1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ( rc == 0 )
							 | 
						||
| 
								 | 
							
								    { int avail = ctx->zstate.avail_in;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													/* copy back unprocessed bytes */
							 | 
						||
| 
								 | 
							
								      DEBUG(1, Sdprintf("GZIP footer ok; copying %d bytes back\n", avail));
							 | 
						||
| 
								 | 
							
								      memmove(ctx->stream->buffer, ctx->zstate.next_in, avail);
							 | 
						||
| 
								 | 
							
								      ctx->stream->bufp   = ctx->stream->buffer;
							 | 
						||
| 
								 | 
							
								      ctx->stream->limitp = ctx->stream->bufp + avail;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return 0;			/* EOF */
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								    { DEBUG(1, Sdprintf("GZIP CRC/length error\n"));
							 | 
						||
| 
								 | 
							
								      return -1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  switch((rc=inflate(&ctx->zstate, Z_NO_FLUSH)))
							 | 
						||
| 
								 | 
							
								  { case Z_OK:
							 | 
						||
| 
								 | 
							
								    case Z_STREAM_END:
							 | 
						||
| 
								 | 
							
								    { long n = (long)(size - ctx->zstate.avail_out);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if ( ctx->format == F_GZIP && n > 0 )
							 | 
						||
| 
								 | 
							
									ctx->crc = crc32(ctx->crc, (Bytef*)buf, n);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if ( rc == Z_STREAM_END )
							 | 
						||
| 
								 | 
							
								      { DEBUG(1, Sdprintf("Z_STREAM_END: %d bytes\n", n));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if ( ctx->format == F_GZIP )
							 | 
						||
| 
								 | 
							
									  ctx->format = F_GZIP_CRC;
							 | 
						||
| 
								 | 
							
								      } else
							 | 
						||
| 
								 | 
							
								      { DEBUG(1, Sdprintf("inflate(): Z_OK: %d bytes\n", n));
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return n;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    case Z_NEED_DICT:
							 | 
						||
| 
								 | 
							
								      DEBUG(1, Sdprintf("Z_NEED_DICT\n"));
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case Z_DATA_ERROR:
							 | 
						||
| 
								 | 
							
								      DEBUG(1, Sdprintf("Z_DATA_ERROR\n"));
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case Z_STREAM_ERROR:
							 | 
						||
| 
								 | 
							
								      DEBUG(1, Sdprintf("Z_STREAM_ERROR\n"));
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case Z_MEM_ERROR:
							 | 
						||
| 
								 | 
							
								      DEBUG(1, Sdprintf("Z_MEM_ERROR\n"));
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    case Z_BUF_ERROR:
							 | 
						||
| 
								 | 
							
								      DEBUG(1, Sdprintf("Z_BUF_ERROR\n"));
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								      DEBUG(1, Sdprintf("Inflate error: %d\n", rc));
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if ( ctx->zstate.msg )
							 | 
						||
| 
								 | 
							
								    Sdprintf("ERROR: zread(): %s\n", ctx->zstate.msg);
							 | 
						||
| 
								 | 
							
								  return -1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static ssize_t				/* deflate */
							 | 
						||
| 
								 | 
							
								zwrite4(void *handle, char *buf, size_t size, int flush)
							 | 
						||
| 
								 | 
							
								{ z_context *ctx = handle;
							 | 
						||
| 
								 | 
							
								  Bytef buffer[SIO_BUFSIZE];
							 | 
						||
| 
								 | 
							
								  int rc;
							 | 
						||
| 
								 | 
							
								  int loops = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ctx->zstate.next_in = (Bytef*)buf;
							 | 
						||
| 
								 | 
							
								  ctx->zstate.avail_in = (long)size;
							 | 
						||
| 
								 | 
							
								  if ( ctx->format == F_GZIP && size > 0 )
							 | 
						||
| 
								 | 
							
								    ctx->crc = crc32(ctx->crc, ctx->zstate.next_in, ctx->zstate.avail_in);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  DEBUG(1, Sdprintf("Compressing %d bytes\n", ctx->zstate.avail_in));
							 | 
						||
| 
								 | 
							
								  do
							 | 
						||
| 
								 | 
							
								  { loops++;
							 | 
						||
| 
								 | 
							
								    ctx->zstate.next_out  = buffer;
							 | 
						||
| 
								 | 
							
								    ctx->zstate.avail_out = sizeof(buffer);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    switch( (rc = deflate(&ctx->zstate, flush)) )
							 | 
						||
| 
								 | 
							
								    { case Z_OK:
							 | 
						||
| 
								 | 
							
								      case Z_STREAM_END:
							 | 
						||
| 
								 | 
							
								      { size_t n = sizeof(buffer) - ctx->zstate.avail_out;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									DEBUG(1, Sdprintf("Compressed (%s) to %d bytes; left %d\n",
							 | 
						||
| 
								 | 
							
											  rc == Z_OK ? "Z_OK" : "Z_STREAM_END",
							 | 
						||
| 
								 | 
							
											  n, ctx->zstate.avail_in));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if ( Sfwrite(buffer, 1, n, ctx->stream) != n )
							 | 
						||
| 
								 | 
							
									  return -1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									break;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      case Z_BUF_ERROR:
							 | 
						||
| 
								 | 
							
									DEBUG(1, Sdprintf("zwrite4(): Z_BUF_ERROR\n"));
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      case Z_STREAM_ERROR:
							 | 
						||
| 
								 | 
							
								      default:
							 | 
						||
| 
								 | 
							
									Sdprintf("ERROR: zwrite(): %s\n", ctx->zstate.msg);
							 | 
						||
| 
								 | 
							
									return -1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  } while ( ctx->zstate.avail_in > 0 ||
							 | 
						||
| 
								 | 
							
									    (flush != Z_NO_FLUSH && rc == Z_OK) );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( flush != Z_NO_FLUSH && Sflush(ctx->stream) < 0 )
							 | 
						||
| 
								 | 
							
								    return -1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return size;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static ssize_t				/* deflate */
							 | 
						||
| 
								 | 
							
								zwrite(void *handle, char *buf, size_t size)
							 | 
						||
| 
								 | 
							
								{ return zwrite4(handle, buf, size, Z_NO_FLUSH);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								zcontrol(void *handle, int op, void *data)
							 | 
						||
| 
								 | 
							
								{ z_context *ctx = handle;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  switch(op)
							 | 
						||
| 
								 | 
							
								  { case SIO_FLUSHOUTPUT:
							 | 
						||
| 
								 | 
							
								      DEBUG(1, Sdprintf("Flushing output\n"));
							 | 
						||
| 
								 | 
							
								      return (int)zwrite4(handle, NULL, 0, Z_SYNC_FLUSH);
							 | 
						||
| 
								 | 
							
								    case SIO_SETENCODING:
							 | 
						||
| 
								 | 
							
								      return 0;				/* allow switching encoding */
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								      if ( ctx->stream->functions->control )
							 | 
						||
| 
								 | 
							
									return (*ctx->stream->functions->control)(ctx->stream->handle, op, data);
							 | 
						||
| 
								 | 
							
								      return -1;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								zclose(void *handle)
							 | 
						||
| 
								 | 
							
								{ z_context *ctx = handle;
							 | 
						||
| 
								 | 
							
								  ssize_t rc;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  DEBUG(1, Sdprintf("zclose() ...\n"));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( (ctx->stream->flags & SIO_INPUT) )
							 | 
						||
| 
								 | 
							
								  { rc = inflateEnd(&ctx->zstate);
							 | 
						||
| 
								 | 
							
								  } else
							 | 
						||
| 
								 | 
							
								  { rc = zwrite4(handle, NULL, 0, Z_FINISH);	/* flush */
							 | 
						||
| 
								 | 
							
								    if ( rc == 0 && ctx->format == F_GZIP )
							 | 
						||
| 
								 | 
							
								      rc = write_gzip_footer(ctx);
							 | 
						||
| 
								 | 
							
								    if ( rc == 0 )
							 | 
						||
| 
								 | 
							
								      rc = deflateEnd(&ctx->zstate);
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								      deflateEnd(&ctx->zstate);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  switch(rc)
							 | 
						||
| 
								 | 
							
								  { case Z_OK:
							 | 
						||
| 
								 | 
							
								      DEBUG(1, Sdprintf("%s(): Z_OK\n",
							 | 
						||
| 
								 | 
							
										        (ctx->stream->flags & SIO_INPUT) ? "inflateEnd"
							 | 
						||
| 
								 | 
							
															 : "deflateEnd"));
							 | 
						||
| 
								 | 
							
								      if ( ctx->close_parent )
							 | 
						||
| 
								 | 
							
								      { IOSTREAM *parent = ctx->stream;
							 | 
						||
| 
								 | 
							
									free_zcontext(ctx);
							 | 
						||
| 
								 | 
							
									return Sclose(parent);
							 | 
						||
| 
								 | 
							
								      } else
							 | 
						||
| 
								 | 
							
								      { free_zcontext(ctx);
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    case Z_STREAM_ERROR:		/* inconsistent state */
							 | 
						||
| 
								 | 
							
								    case Z_DATA_ERROR:			/* premature end */
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								      if ( ctx->close_parent )
							 | 
						||
| 
								 | 
							
								      { IOSTREAM *parent = ctx->stream;
							 | 
						||
| 
								 | 
							
									free_zcontext(ctx);
							 | 
						||
| 
								 | 
							
									Sclose(parent);
							 | 
						||
| 
								 | 
							
									return -1;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      free_zcontext(ctx);
							 | 
						||
| 
								 | 
							
								      return -1;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static IOFUNCTIONS zfunctions =
							 | 
						||
| 
								 | 
							
								{ zread,
							 | 
						||
| 
								 | 
							
								  zwrite,
							 | 
						||
| 
								 | 
							
								  NULL,					/* seek */
							 | 
						||
| 
								 | 
							
								  zclose,
							 | 
						||
| 
								 | 
							
								  zcontrol,				/* zcontrol */
							 | 
						||
| 
								 | 
							
								  NULL,					/* seek64 */
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	 PROLOG CONNECTION	*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define COPY_FLAGS (SIO_INPUT|SIO_OUTPUT| \
							 | 
						||
| 
								 | 
							
										    SIO_TEXT| \
							 | 
						||
| 
								 | 
							
										    SIO_REPXML|SIO_REPPL|\
							 | 
						||
| 
								 | 
							
										    SIO_RECORDPOS)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static foreign_t
							 | 
						||
| 
								 | 
							
								pl_zopen(term_t org, term_t new, term_t options)
							 | 
						||
| 
								 | 
							
								{ term_t tail = PL_copy_term_ref(options);
							 | 
						||
| 
								 | 
							
								  term_t head = PL_new_term_ref();
							 | 
						||
| 
								 | 
							
								  z_context *ctx;
							 | 
						||
| 
								 | 
							
								  zformat fmt = F_UNKNOWN;
							 | 
						||
| 
								 | 
							
								  int level = Z_DEFAULT_COMPRESSION;
							 | 
						||
| 
								 | 
							
								  IOSTREAM *s, *s2;
							 | 
						||
| 
								 | 
							
								  int close_parent = TRUE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while(PL_get_list(tail, head, tail))
							 | 
						||
| 
								 | 
							
								  { atom_t name;
							 | 
						||
| 
								 | 
							
								    int arity;
							 | 
						||
| 
								 | 
							
								    term_t arg = PL_new_term_ref();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ( !PL_get_name_arity(head, &name, &arity) || arity != 1 )
							 | 
						||
| 
								 | 
							
								      return type_error(head, "option");
							 | 
						||
| 
								 | 
							
								    _PL_get_arg(1, head, arg);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ( name == ATOM_format )
							 | 
						||
| 
								 | 
							
								    { atom_t a;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if ( !get_atom_ex(arg, &a) )
							 | 
						||
| 
								 | 
							
									return FALSE;
							 | 
						||
| 
								 | 
							
								      if ( a == ATOM_gzip )
							 | 
						||
| 
								 | 
							
									fmt = F_GZIP;
							 | 
						||
| 
								 | 
							
								      else if ( a == ATOM_deflate )
							 | 
						||
| 
								 | 
							
									fmt = F_DEFLATE;
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
									return domain_error(arg, "compression_format");
							 | 
						||
| 
								 | 
							
								    } else if ( name == ATOM_level )
							 | 
						||
| 
								 | 
							
								    { if ( !get_int_ex(arg, &level) )
							 | 
						||
| 
								 | 
							
									return FALSE;
							 | 
						||
| 
								 | 
							
								      if ( level < 0 || level > 9 )
							 | 
						||
| 
								 | 
							
									return domain_error(arg, "compression_level");
							 | 
						||
| 
								 | 
							
								    } else if ( name == ATOM_close_parent )
							 | 
						||
| 
								 | 
							
								    { if ( !get_bool_ex(arg, &close_parent) )
							 | 
						||
| 
								 | 
							
									return FALSE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if ( !PL_get_nil(tail) )
							 | 
						||
| 
								 | 
							
								    return type_error(tail, "list");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( !PL_get_stream_handle(org, &s) )
							 | 
						||
| 
								 | 
							
								    return FALSE;			/* Error */
							 | 
						||
| 
								 | 
							
								  ctx = alloc_zcontext(s);
							 | 
						||
| 
								 | 
							
								  ctx->close_parent = close_parent;
							 | 
						||
| 
								 | 
							
								  ctx->format = fmt;
							 | 
						||
| 
								 | 
							
								  if ( (s->flags & SIO_OUTPUT) )
							 | 
						||
| 
								 | 
							
								  { int rc;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ( fmt == F_GZIP )
							 | 
						||
| 
								 | 
							
								    { if ( write_gzip_header(ctx) < 0 )
							 | 
						||
| 
								 | 
							
								      { free_zcontext(ctx);
							 | 
						||
| 
								 | 
							
									return FALSE;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      rc = deflateInit2(&ctx->zstate, level, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0);
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								    { rc = deflateInit(&ctx->zstate, level);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ( rc != Z_OK )
							 | 
						||
| 
								 | 
							
								    { free_zcontext(ctx);
							 | 
						||
| 
								 | 
							
								      return FALSE;			/* TBD: Error */
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( !(s2 = Snew(ctx,
							 | 
						||
| 
								 | 
							
										   (s->flags©_FLAGS)|SIO_FBUF,
							 | 
						||
| 
								 | 
							
										   &zfunctions))	)
							 | 
						||
| 
								 | 
							
								  { free_zcontext(ctx);			/* no memory */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return FALSE;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  s2->encoding = s->encoding;
							 | 
						||
| 
								 | 
							
								  ctx->zstream = s2;
							 | 
						||
| 
								 | 
							
								  Sset_filter(s, s2);
							 | 
						||
| 
								 | 
							
								  PL_release_stream(s);
							 | 
						||
| 
								 | 
							
								  if ( PL_unify_stream(new, s2) )
							 | 
						||
| 
								 | 
							
								  { return TRUE;
							 | 
						||
| 
								 | 
							
								  } else
							 | 
						||
| 
								 | 
							
								  { ctx->close_parent = FALSE;
							 | 
						||
| 
								 | 
							
								    Sclose(s2);
							 | 
						||
| 
								 | 
							
								    return instantiation_error();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef O_DEBUG
							 | 
						||
| 
								 | 
							
								static foreign_t
							 | 
						||
| 
								 | 
							
								zdebug(term_t level)
							 | 
						||
| 
								 | 
							
								{ return PL_get_integer(level, &debuglevel);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	       INSTALL		*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define MKFUNCTOR(name, arity) PL_new_functor(PL_new_atom(name), arity)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								install_t
							 | 
						||
| 
								 | 
							
								install_zlib4pl()
							 | 
						||
| 
								 | 
							
								{ FUNCTOR_error2        = MKFUNCTOR("error", 2);
							 | 
						||
| 
								 | 
							
								  FUNCTOR_type_error2   = MKFUNCTOR("type_error", 2);
							 | 
						||
| 
								 | 
							
								  FUNCTOR_domain_error2 = MKFUNCTOR("domain_error", 2);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ATOM_format       = PL_new_atom("format");
							 | 
						||
| 
								 | 
							
								  ATOM_level        = PL_new_atom("level");
							 | 
						||
| 
								 | 
							
								  ATOM_close_parent = PL_new_atom("close_parent");
							 | 
						||
| 
								 | 
							
								  ATOM_gzip	    = PL_new_atom("gzip");
							 | 
						||
| 
								 | 
							
								  ATOM_deflate	    = PL_new_atom("deflate");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  PL_register_foreign("zopen",  3, pl_zopen,  0);
							 | 
						||
| 
								 | 
							
								#ifdef O_DEBUG
							 | 
						||
| 
								 | 
							
								  PL_register_foreign("zdebug", 1, zdebug, 0);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								}
							 |