Initializing help system before first use

Using the 'zlib' library to provide IO driver 'compress' functionality


Type: Programming
Rating: 4 (medium-difficult)
Description: This example module uses the 'zlib' library (see: http://www.gzip.org) to provide the I/O driver 'compress' (e.g. "zlib.compress:model.bim") for stream compression and 'gzip' (e.g. "zlib.gzip:data.gz") for handling gzip files.
Language extensions provided by this module:
  • service: 2 I/O drivers
File(s): zlib.c


zlib.c
/******************************************
  Mosel NI Examples
  =================
    
  File zlib.c
  ```````````
  Example module defining an IO driver
  for (un)compression using zlib library
  which can be found at http://www.zlib.org

  (c) 2008 Fair Isaac Corporation
      author: Y. Colombani, 2003
  zlib:
  (c) 1995-2002 Jean-Loup Gailly and Mark Adler
*******************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define XPRM_NICOMPAT 3004002           /* Compatibility level: Mosel 3.4.2 */
#include "xprm_ni.h"

#ifdef _WIN32
#define snprintf _snprintf
#define _WINDOWS
#define ZLIB_DLL
   /* for precompiled zlib 1.2.1 */
#define ZLIB_WINAPI
#endif
#include "zlib.h"

#define BUFSIZE 1024                    /* buffer size for data transfer */

/**************************************************/
/* gzip driver: to handle files using GZIP format */
/* Example: "zlib.gzip:mydata.gz"                 */
/**************************************************/
                                        /* Functions of 'gzip' driver */
static void *gzip_open(XPRMcontext ctx,int *mode,const char *fname);
static int gzip_close(XPRMcontext ctx,gzFile gzf,int mode);
static long gzip_read(XPRMcontext ctx,gzFile gzf,void *buffer,
                                                        unsigned long size);
static long gzip_write(XPRMcontext ctx,gzFile gzf,void *buffer,
                                                        unsigned long size);
static void  setgzerror(XPRMcontext ctx,gzFile gzf);
static XPRMiofcttab iodrv_gzip[]=
        {
         {XPRM_IOCTRL_OPEN,gzip_open},
         {XPRM_IOCTRL_CLOSE,gzip_close},
         {XPRM_IOCTRL_READ,gzip_read},
         {XPRM_IOCTRL_WRITE,gzip_write},
         {XPRM_IOCTRL_INFO,"filename"},
         {0,NULL}
        };

/*************************************************/
/* compress driver: to handle compressed streams */
/* As opposed to 'gzip' driver this driver does  */
/* not require a physical file                   */
/* Note also that files produced by this driver  */
/* are not compatible with gzip                  */
/* Example: "zlib.compress:mem:0x1234/256"       */
/**************************************************/
                                        /* Functions of 'compress' driver */
static void *comp_open(XPRMcontext ctx,int *mode,const char *fname);
static int comp_close(XPRMcontext ctx,z_streamp zstr,int mode);
static long comp_read(XPRMcontext ctx,z_streamp zstr,void *buffer,
                                                        unsigned long size);
static long comp_write(XPRMcontext ctx,z_streamp zstr,void *buffer,
                                                        unsigned long size);
static XPRMiofcttab iodrv_compress[]=
        {
         {XPRM_IOCTRL_OPEN,comp_open},
         {XPRM_IOCTRL_CLOSE,comp_close},
         {XPRM_IOCTRL_READ,comp_read},
         {XPRM_IOCTRL_WRITE,comp_write},
         {XPRM_IOCTRL_INFO,"extended_filename"},
         {0,NULL}
        };

                                     /* Drivers of zlib module: gzip,compress */
static XPRMiodrvtab iodrv_zlib[]=
        {
         {"gzip",iodrv_gzip},
         {"compress",iodrv_compress},
         {NULL,NULL}
        };

static int chkres(int);
                                     /* Table of services: only IO drivers */
static XPRMdsoserv tabserv[]=
        {
         {XPRM_SRV_IODRVS,iodrv_zlib},
         {XPRM_SRV_CHKRES,(void*)chkres}
        };

                                     /* DSO interface: only services */
static XPRMdsointer dsointer= 
        { 
         0,NULL,
         0,NULL,
         0,NULL,
         sizeof(tabserv)/sizeof(mm_dsoserv),tabserv
        };

static XPRMnifct mm;             /* For storing Mosel NI function table */

/************************************************/
/* Initialize the library just after loading it */
/************************************************/
DSO_INIT zlib_init(XPRMnifct nifct, int *interver,int *libver, XPRMdsointer **interf)
{
 const char *zlv;

 mm=nifct;                      /* Save the table of Mosel NI functions */
 *interver=XPRM_NIVERS;         /* The interface version we are using */

                                /* We check ZLIB library version here */
 zlv=zlibVersion();
 if((zlv==NULL)||(zlv[0]!=ZLIB_VERSION[0]))
 {
  mm->dispmsg(NULL,"ZLIB: wrong version (expect %s got %s).\n",ZLIB_VERSION,
                                                          (zlv!=NULL)?zlv:"0");
  return 1;
 }
 else
 {
  *libver=XPRM_MKVER(0,0,2);     /* The version of the module: 0.0.2 */
  *interf=&dsointer;             /* Our interface */
  return 0;
 }
}

/****************************************************************/
/* Check restrictions (this module implements all restrictions) */
/****************************************************************/
static int chkres(int r)
{
 return 0;
}

/****************************************/
/* Open a gzip-file for (de)compression */
/****************************************/
static void *gzip_open(XPRMcontext ctx,int *mode,const char *fname)
{
 char cfname[MM_MAXPATHLEN];
 char cmode[16];
 int cml;
 void *gzf;

 if((fname==NULL)||
    (mm->pathcheck(ctx,fname,cfname,MM_MAXPATHLEN,
    ((*mode)&MM_F_WRITE)?MM_RCHK_WRITE:MM_RCHK_READ)!=0))
 {
  mm->setioerrmsg(ctx,strerror(EACCES),1);
  return NULL;
 }
 else
 {
  cml=2;
  cmode[0]=((*mode)&MM_F_WRITE)?'w':'r';
  cmode[1]=((*mode)&MM_F_BINARY)?'b':'t';
  if((*mode)&MM_F_APPEND) cmode[cml++]='a';
  cmode[cml]='\0';
  gzf=gzopen(cfname,cmode);
  if(gzf==NULL)
   mm->setioerrmsg(ctx,strerror(errno),2);
  return gzf;
 }
}

/***********************/
/* Close the gzip-file */
/***********************/
static int gzip_close(XPRMcontext ctx,gzFile gzf,int mode)
{ return gzclose(gzf); }

/******************************/
/* Uncompress a block of data */
/******************************/
static long gzip_read(XPRMcontext ctx,gzFile gzf,void *buffer,
                                                        unsigned long size)
{
 long l;

 l=gzread(gzf,buffer,size);
 if(l<0) setgzerror(ctx,gzf);
 return l;
}

/****************************/
/* Compress a block of data */
/****************************/
static long gzip_write(XPRMcontext ctx,gzFile gzf,void *buffer,
                                                        unsigned long size)
{
 long l;
 
 l=gzwrite(gzf,buffer,size);
 if(l<=0) setgzerror(ctx,gzf);
 return l;
}

/*********************************/
/* Set message of the last error */
/*********************************/
static void  setgzerror(XPRMcontext ctx,gzFile gzf)
{
 int errnum;
 const char *emsg;

 if((((emsg=gzerror(gzf,&errnum))!=NULL)&&(errnum==Z_ERRNO)))
 {
  errnum=errno;
  emsg=strerror(errno);
 }
 if(errnum!=0)
  mm->setioerrmsg(ctx,emsg,errnum);
}

/*************************************/
/* Open a stream for (de)compression */
/*************************************/
static void *comp_open(XPRMcontext ctx,int *mode,const char *fname)
{
 z_streamp zstr;
 int rts;

                                /* 1st: open actual file */
 if(mm->fopen(ctx,((*mode)&XPRM_F_WRITE)|XPRM_F_BINARY,fname)<0)
 {
  *mode|=XPRM_F_SILENT;                 /* Error message already displayed */
                                        /* switch so silent mode */
  return NULL;
 }
 else
 {                                 /* If OK, prepare data structures for zlib */
                /* Allocate memory for zstream and a buffer */
  if((zstr=(z_streamp)malloc(sizeof(z_stream)+BUFSIZE))==NULL)
  {
   mm->fclose(ctx,(*mode)&(XPRM_F_READ|XPRM_F_WRITE));
   mm->setioerrmsg(ctx,"Not enough memory",1);
   return NULL;
  }
  memset(zstr,0,sizeof(z_stream));
  zstr->zalloc=Z_NULL;
  zstr->zfree=Z_NULL;
  
  if(((*mode)&(XPRM_F_READ|XPRM_F_WRITE))==XPRM_F_READ)
  {                             /* For reading: 'inflate' algorithm */
   rts=inflateInit(zstr);
   zstr->next_in=(void *)(zstr+1);      /* Buffer is after zstream */
  }
  else
  {                             /* For writing: 'deflate' algorithm */
   rts=deflateInit(zstr,Z_DEFAULT_COMPRESSION);
   zstr->next_out=(void *)(zstr+1);     /* Buffer is after zstream */
   zstr->avail_out=BUFSIZE;
  }

  if(rts!=Z_OK)
  {
   mm->setioerrmsg(ctx,zstr->msg,rts);
   free(zstr);
   mm->fclose(ctx,(*mode)&(XPRM_F_READ|XPRM_F_WRITE));
   return NULL;
  }
  else
   return zstr;
 }
}

/********************/
/* Close the stream */
/********************/
static int comp_close(XPRMcontext ctx,z_stream *zstr,int mode)
{
 int rts1,rts2;
 Bytef dummy;

 if((mode&(XPRM_F_READ|XPRM_F_WRITE))==XPRM_F_READ)
 {                      /* If reading: just release zstream */
  rts1=inflateEnd(zstr);
 }
 else
 {                      /* If writing: buffers have to be flushed first */
  zstr->next_in=&dummy;
  zstr->avail_in=0;
  if(zstr->avail_out==0)
  {
   mm->fwrite(ctx,zstr+1,BUFSIZE);
   zstr->next_out=(void *)(zstr+1);
   zstr->avail_out=BUFSIZE;
  }
  do
  {
   rts1=deflate(zstr,Z_FINISH);
   if(BUFSIZE-zstr->avail_out>0)
    mm->fwrite(ctx,zstr+1,BUFSIZE-zstr->avail_out);
   zstr->next_out=(void *)(zstr+1);
   zstr->avail_out=BUFSIZE;
  } while(rts1==Z_OK);
  
  rts1=deflateEnd(zstr);
 }
                        /* Finally close actual file and release memory */
 rts2=mm->fclose(ctx,mode);
 if(rts1!=Z_OK)
  mm->setioerrmsg(ctx,zstr->msg,rts1);
 free(zstr);
 return (rts1!=Z_OK)||(rts2!=0);
}

/******************************/
/* Uncompress a block of data */
/******************************/
static long comp_read(XPRMcontext ctx,z_stream *zstr,void *buffer,
                                                        unsigned long size)
{
 int rts,finish;

 zstr->next_out=buffer;
 zstr->avail_out=size;
 finish=0;
 do
 {
  if(zstr->avail_in==0)
  {
   zstr->avail_in=mm->fread(ctx,zstr+1,BUFSIZE);
   zstr->next_in=(void *)(zstr+1);
   finish=(zstr->avail_in==0);
  }
  rts=inflate(zstr,Z_NO_FLUSH);
 } while((rts==Z_OK)&&(zstr->avail_out>0) && !finish);
 if(finish && (zstr->avail_out>0))
  rts=inflate(zstr,Z_SYNC_FLUSH);
 if((rts==Z_OK)||(rts==Z_STREAM_END))
  return (long)(size-zstr->avail_out);
 else
 {
  mm->setioerrmsg(ctx,zstr->msg,rts);
  return -1;
 }
}

/****************************/
/* Compress a block of data */
/****************************/
static long comp_write(XPRMcontext ctx,z_stream *zstr,void *buffer,
                                                        unsigned long size)
{
 int rts;

 zstr->next_in=buffer;
 zstr->avail_in=size;
 do
 {
  if(zstr->avail_out==0)
  {
   mm->fwrite(ctx,zstr+1,BUFSIZE);
   zstr->next_out=(void *)(zstr+1);
   zstr->avail_out=BUFSIZE;
  }
  rts=deflate(zstr,Z_NO_FLUSH);
 } while((rts==Z_OK)&&(zstr->avail_in>0));
 if(rts==Z_OK)
  return 1;
 else
 {
  mm->setioerrmsg(ctx,zstr->msg,rts);
  return 0;
 }
}