Example Source Code: hhdbzip.c


/*
  **********************************************************************
  * hhdbzip.c                                                          *
  * Copyright (C) 1997 Dept. of Mathematics, University of Houston     *
  * This is free software; you can use, copy, distribute and/or modify *
  * it freely under the disclaimer that no warranties are offered nor  *
  * liabilities assumed through such actions.                          *
  **********************************************************************
  ************************************************
> hhdbzip fname
  Compresses a binary file composed of 4-byte 
  ints and 4-byte floats. Result is fname.hgz
> hhdbzip -r fname.hgz
  Recovers the associated file fname.

Must have 4 byte ints [MS-byte,,,LS-byte], and 
4 byte ieee floats [sign-bit,exp,frac] with 8 
bits of exp (0-255 normalized) and 23 frac bits.
************************************************/

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

/*#define DEBUG*/

#define GZIP   "gzip -c > "
#define GUNZIP "gzip -cd "

#define MAGIC_NUMBER  1212432974
#define EXPONENT_MASK (255<<23)

#define SPLIT(val,buf0,buf1,buf2,buf3) {    \
          unsigned int  split4;             \
          split4 = *((unsigned int*)&(val));\
          buf3 = 255 & split4;              \
          split4 >>= 8;                     \
          buf2 = 255 & split4;              \
          split4 >>= 8;                     \
          if( 32768 & split4 )              \
            buf1 = (127 & split4) | 128;    \
          else                              \
            buf1 = (127 & split4);          \
          split4 >>= 7;                     \
          buf0 = (255 & split4);            \
        }

#define UNSPLIT(val,buf0,buf1,buf2,buf3) {  \
          if( 128 & buf1 )                  \
            val = ((unsigned int)1<<31)     \
                  |((buf1)&127)<<16;        \
          else                              \
            val = (buf1)<<16;               \
          val |= ((buf0)<<23)               \
                |((buf2)<<8)|(buf3);        \
        } 

/***************************************************************/

main(argc,argv)
int  argc;
char *argv[];
{
  FILE *finp,*foutp,*pout,*pin;
  char *fin,mode,fout[256],pcmd[512];
  int  size,status,n,nints,nflts;
  unsigned char *buf,
                *exps,
                *ints1,*ints2,*ints3,
                *flts1,*flts2,*flts3;

  if( sizeof(int) != 4 || sizeof(float) != 4 ) {
    fprintf(stderr,"Ints and flts are not 4 bytes.\n");
    fprintf(stderr,"Sorry...\n");
    exit(1);
  }  

  if( argc < 2 ) {
    fprintf(stderr,"Usage: %s fname [-r]\n",argv[0]); 
    exit(1);
  }
  mode = 'c';
  fin  = NULL;
  for( n = 1; n < argc; n++) {
    char *arg;

    arg = argv[n];
    if( arg[0] == '-' ) {
      if( arg[1] == 'r' )
        mode = 'r';
      else {
        fprintf(stderr,"Usage: %s fname [-r]\n",argv[0]); 
        exit(1);  
      }
    }
    else
      fin = arg;
  }
  if( !fin ) {
    fprintf(stderr,"Usage: %s fname [-r]\n",argv[0]); 
    exit(1);  
  }
  if( mode == 'r' ) goto Recover;


/*** Compress ***/
  finp = fopen(fin,"rb");
  if( !finp ) {
    fprintf(stderr,"Error opening input file %s.\n",fin);
    exit(1);
  }
  fseek(finp,(long)0,SEEK_END);
  size = ftell(finp);
  fseek(finp,(long)0,SEEK_SET);
  if( size & 3 ) {
    fprintf(stderr,"Size of %s is not a multiple of 4.\n",fin);
    goto CError;
  }    
  size = size/4;

  buf = (unsigned char*)malloc(12+size+3*size+3*size);
  if( !buf ) {
    fprintf(stderr,"Error allocating memory.\n");
    goto CError;
  }
  exps  = buf+12;
  ints1 = exps+size;
  ints2 = ints1+size;
  ints3 = ints2+size;
  flts1 = ints3+size;
  flts2 = flts1+size;
  flts3 = flts2+size;

  n = nints = nflts = 0;
  while( 1 ) {
    unsigned int val;

    status = fread(&val,4,1,finp);
    switch( status ) {
    case 1:
      switch( val & EXPONENT_MASK ) {
      case 0:
      case EXPONENT_MASK:
#ifdef DEBUG
        { int *ival=(int*)&val;
          printf("int = %d\n",*ival);
        }
#endif
        SPLIT(val,exps[n],ints1[nints],ints2[nints],ints3[nints]);
        n++; nints++;
        break;
      default:
#ifdef DEBUG
        { float *rval=(float*)&val;
          printf("flt = %f\n",*rval);
        }
#endif
        SPLIT(val,exps[n],flts1[nflts],flts2[nflts],flts3[nflts]);
        n++; nflts++;
      }
      break;
    case 0:
      if( feof(finp) ) goto Done;
    default:
      fprintf(stderr,"Error reading word from %s.\n",fin);
      goto CError;
    }
  }

Done:
  fclose(finp);
  strcpy(pcmd,GZIP);
  status = strlen(pcmd)+strlen(fin)+5;
  if( status > 512 ) {
    fprintf(stderr,"Output file name %s.hgz is too long.\n",fin);
    exit(1);
  }
  strcat(pcmd,fin);
  strcat(pcmd,".hgz");
  pout = (FILE*)popen(pcmd,"wb");
  if( !pout ) {
    fprintf(stderr,"Error starting %s\n",pcmd);
    exit(1);
  }
  ((unsigned int*)buf)[0] = MAGIC_NUMBER;
  ((unsigned int*)buf)[1] = nints;
  ((unsigned int*)buf)[2] = nflts;
  fwrite(buf,1,12+size,pout);
  fwrite(ints1,1,nints,pout);
  fwrite(ints2,1,nints,pout);
  fwrite(ints3,1,nints,pout);
  fwrite(flts1,1,nflts,pout);
  fwrite(flts2,1,nflts,pout);
  fwrite(flts3,1,nflts,pout);
  free(buf);
  exit(pclose(pout));

CError:
  fclose(finp);
  exit(1);


/*** Uncompress ***/
Recover:
  status = strlen(fin);
  if( status >= 4 && status < 256 ) {
    if( strcmp(&fin[status-4],".hgz") == 0 ) {
      strncpy(fout,fin,status-4);
      fout[status-4] = '\0';
    }
    else {
      fprintf(stderr,"Incorrect filename suffix.\n");
      exit(1);
    }
  }
  else {
    fprintf(stderr,"Incorrect filename suffix.\n");
    exit(1);
  }

  foutp = fopen(fout,"wb");
  if( !foutp ) {
    fprintf(stderr,"Can not open %s for writing.\n",fout);
    exit(1);
  }

  strcpy(pcmd,GUNZIP);
  status = strlen(pcmd)+strlen(fin)+1;
  if( status > 512 ) {
    fprintf(stderr,"Input file name is too long.\n",fin);
    goto RError;
  }
  strcat(pcmd,fin);
  pin = (FILE*)popen(pcmd,"rb");
  if( !pout ) {
    fprintf(stderr,"Error starting %s\n",pcmd);
    goto RError;
  }
  if( fread(&status,4,1,pin) != 1 || status != MAGIC_NUMBER ) {
    fprintf(stderr,"%s has incorrect magic number.\n",fin);
    pclose(pin);
    goto RError;
  }
  fread(&nints,4,1,pin);
  fread(&nflts,4,1,pin);
  size = (nints+nflts);
  buf = (unsigned char*)malloc(4*size);
  if( !buf ) {
    fprintf(stderr,"Error allocating memory.\n");
    pclose(pin);
    goto RError;
  }
  if( fread(buf,4,size,pin) != size ) {
    fprintf(stderr,"Error uncompressing data.\n");
    pclose(pin);
    goto RError;
  }
  if( pclose(pin) ) {
    fprintf(stderr,"Error uncompressing data.\n");
    goto RError;
  }

  exps  = buf;
  ints1 = exps+size;
  ints2 = ints1+nints;
  ints3 = ints2+nints;
  flts1 = ints3+nints;
  flts2 = flts1+nflts;
  flts3 = flts2+nflts;

  for(n = 0; n < size; n++) {
    unsigned int val;

    switch( *exps ) {
    case   0:
    case 255:
      UNSPLIT(val,*exps,*ints1,*ints2,*ints3);
#ifdef DEBUG
      { int *ival=(int*)&val;
        printf("int = %d (%d %d %d %d)\n",*ival,*exps,*ints1,*ints2,*ints3);
      }
#else
      fwrite(&val,4,1,foutp);
#endif
      exps++; ints1++; ints2++; ints3++;
      break;
    default:
      UNSPLIT(val,*exps,*flts1,*flts2,*flts3);
#ifdef DEBUG
      { float *rval=(float*)&val;
        printf("flt = %f (%d %d %d %d)\n",*rval,*exps,*flts1,*flts2,*flts3);
      }
#else
      fwrite(&val,4,1,foutp);
#endif
      exps++; flts1++; flts2++; flts3++;
    }
  }    
  fclose(foutp);
  free(buf);
  exit(0);

RError:
  fclose(foutp);
  exit(1);

}

Last modified: Mon Sep 14 11:22:01 MET DST 1998