/********************************************************************
* ucnids - NIDS decompression utility for data compressed with zlib
*
*   syntax: ucnids [options] ifile ofile
*   ifile and ofile can be "-" to use standard input and output
*   options: 
*     none - output uncompressed product with NOAAPORT CCB
*     -c   - output with standard WMO CCB
*     -w   - output with WXP-like WMO header
*     -n   - output stripping header and leaving raw NIDS data
********************************************************************/
#include <stdio.h>
#include <zlib.h>

main( int argc, char **argv ){
   FILE *ifile;
   FILE *ofile;
   unsigned char soh[101];
   unsigned char seq[101];
   unsigned char wmo[101];
   unsigned char awip[101];
   unsigned char inbuf[1000];
   unsigned int insize;
   unsigned char outbuf[10000];
   z_stream zs;
   int out;
   int len;
   int iret;
   int off;
   int i;
   int wxp;

   off = 0;
   if( argc > 1 && !strcmp( argv[1], "-c" )){
      out = 1;
      off++;
      }
   if( argc > 1 && !strcmp( argv[1], "-w" )){
      out = 2;
      off++;
      }
   if( argc > 1 && !strcmp( argv[1], "-n" )){
      out = 3;
      off++;
      }
   if( argc == 1+off || argv[1+off][0] == '-' )
      ifile = stdin;
   else
      ifile = fopen( argv[1+off], "r" );
   if( ifile == NULL ) exit( 1 );

   if( argc < 3+off || argv[2+off][0] == '-' )
      ofile = stdin;
   else
      ofile = fopen( argv[2+off], "w" );

  
   fgets( soh, 100, ifile );
   /*
      Account for both raw input (0x01) and WXP input (**)
   */
   wxp = 0;
   off = 0;
   if( soh[0] == 0x78 && soh[1] == 0x9C ){
      off = strlen( soh );
      memcpy( inbuf, soh, off );
      }
   else if( soh[0] == '\n' ){
      fgets( soh, 100, ifile );
      len = strlen( soh )-7;
      memcpy( wmo, soh+3, len );
      wmo[len] = 0;
      fgets( awip, 100, ifile );
      wxp = 1;
      }
   else if( soh[0] == '*' ){
      len = strlen( soh )-7;
      memcpy( wmo, soh+3, len );
      wmo[len] = 0;
      fgets( awip, 100, ifile );
      wxp = 1;
      }
   else if( soh[0] == 0x01 ){
      fgets( seq, 100, ifile );
      fgets( wmo, 100, ifile );
      fgets( awip, 100, ifile );
      }

   iret = 0;
   zs.total_out = 4000;
   
   for( i = 0; iret != Z_STREAM_END || zs.total_out == 4000; i++ ){
      /* 
         Read in a block of data
      */
      insize = fread( inbuf+off, 1, 1000-off, ifile ); 
      len = insize + off;
      /* 
         Check for 789C byte sequence denoting zlib compression
         If data are not compressed, pass through raw data
      */
      if( i == 0 && ( inbuf[0] != 0x78 || inbuf[1] != 0x9C )){
          if( wxp ){
             fprintf( ofile, soh );
             fprintf( ofile, awip );
             }
          else {
             fprintf( ofile, soh );
             fprintf( ofile, seq );
             fprintf( ofile, wmo );
             fprintf( ofile, awip );
             }
          fwrite( inbuf, 1, insize, ofile );
          while(( insize = fread( inbuf, 1, 1000, ifile )) > 0 ){
             fwrite( inbuf, 1, insize, ofile );
             }
          exit( 0 );
          }
      zs.avail_in = len;
      zs.avail_out = 10000;
      zs.next_in = inbuf;
      zs.next_out = outbuf;
      /*
         Check to see if 4000 byte block has been read and reinitialize
      */
      if( i == 0 || iret == Z_STREAM_END ){
         zs.zalloc = NULL;
         zs.zfree = NULL;
         inflateInit( &zs );
         }
      /*
         Inflate NIDS data
      */
      iret = inflate( &zs, Z_STREAM_END );
      off = zs.avail_in;
      /*  
         Process header data for first block
         WMO CCB output
      */
      if( i == 0 && out == 1 ){
         fwrite( "\001\r\r\n001\r\r\n", 1, 10, ofile );
         fwrite( outbuf+24, 1, 10000-zs.avail_out-24, ofile );
         } 
      /*
         WXP header output
      */
      else if( i == 0 && out == 2 ){
         fprintf( ofile, "** %18.18s ***\n%s", wmo, awip );
         fwrite( outbuf+54, 1, 10000-zs.avail_out-54, ofile );
         } 
      /*
         Raw NIDS output
      */
      else if( i == 0 && out == 3 ){
         fwrite( outbuf+54, 1, 10000-zs.avail_out-54, ofile );
         } 
      /*
         Raw output with NOAAPORT CCB
      */
      else 
         fwrite( outbuf, 1, 10000-zs.avail_out, ofile );
      /*
         Move remaining data that still is compressed and prepared 
         for next inflate
      */
      memcpy( inbuf, inbuf+len-off, off );
      }
   }
