F /********************************************************************/F /*  Image Decompression Program - C Version for PC, VAX, Unix       */F /*  and Macintosh systems.                                          */F /*                                                                  */F /*  Decompresses images using Kris Becker's subroutine DECOMP.C     */F /*  which is included in this program in a shortened version.       */F /*                                                                  */F /*  Reads a variable length compressed PDS image and outputs a      */F /*  fixed length uncompressed image file in PDS format with         */F /*  labels, image histogram, engineering table, line header table   */F /*  and an image with PDS, FITS, VICAR or no labels.  If used on    */F /*  a non-byte-swapped machine the image histogram is un-swapped.   */F /*                                                                  */F /********************************************************************/F /*                                                                  */F /*  Use the following commands to compile and link to produce an    */F /*  executable file:                                                */F /*                                                                  */F /*  On an IBM PC (using Microsoft C Version 5.x)                    */F /*                                                                  */F /*    cl /c vdcomp.c                                                */F /*    link  vdcomp/stack:10000;                                     */F /*                                                                  */F /*  On a VAX:                                                       */F /*                                                                  */F /*    cc   vdcomp                                                   */F /*    $define lnk$library sys$library:vaxcrtl.olb                   */F /*    link vdcomp                                                   */F /*                                                                  */F /*  On a Unix host (Sun, Masscomp)                                  */F /*                                                                  */F /*    cc -o vdcomp vdcomp.c                                         */F /*                                                                  */F /*  On a Macintosh (using Lightspeed C)                             */F /*                                                                  */F /*    link with the following libraries:                            */F /*    stdio, storage, strings, unix and MacTraps, with MacTraps     */F /*    and vdcomp in a separate segment.                             */F /*                                                                  */F /********************************************************************/F /*                                                                  */F /*  Use the following command to run the program:                   */F /*                                                                  */F /*    VDCOMP [infile] [outfile] [output format]                     */F /*                                                                  */F /*       infile        - name of compressed image file.             */F /*       outfile       - name of uncompressed output file.          */F /*       output format - selected from the following list:          */F /*                                                                  */F /*          1  SFDU/PDS format [DEFAULT].                           */F /*          2  FITS format.                                         */F /*          3  VICAR format.                                        */F /*          4  Unlabelled binary array.                             */F /*                                                                  */F /*  On the VAX computer you will need to 'install' the program to   */F /*  be able to use command line arguments using the following       */F /*  command:                                                        */F /*                                                                  */F /*  $ vdcomp :== $DISKNAME:[DIRECTORY]vdcomp.exe                    */F /*                                                                  */F /*  where DISKNAME is the disk drive and DIRECTORY is the           */F /*  directory where VDCOMP.EXE is stored.                           */F /*                                                                  */F /********************************************************************/F /*                                                                  */F /* LIMS                                                             */F /*  This program has been tested on a VAX 780 (VMS 4.6), SUN        */F /*  Workstation (UNIX 4.2, release 3.4), an IBM PC                  */F /*  (MICROSOFT 5.1 compiler) and Macintosh IIx using Lightspeed C   */F /*  version 3.0.  When converting to other systems, check for       */F /*  portability conflicts.                                          */F /*                                                                  */F /* HIST                                                             */F /*  DEC89 Modified program to handle both Voyager and Viking images.*/F /*  OCT89 Converted Voyager decompression program to handle Viking  */F /*  compressed images.  Changed obuf to 'unsigned' to simplify      */F /*  computation of checksum.                                        */F /*  AUG89 Added code to get command line arguments for filenames    */F /*  and output format; routines to free memory used by the Huffman  */F /*  tree); fixed the SFDU label output length; and modified the     */F /*  I/O routines so that the open for Host type 2 uses binary I/O.  */F /*  JUN89 Fixed READVAR, to get length on 16-bit unswapped hosts.   */F /*  JUL88 C driver to decompress standard Voyager Compressed images */F /*  by Mike Martin 1989/12/02                                       */F /*                                                                  */F /*  Inputs   - Input file to be decompressed.                       */F /*                                                                  */F /*  Outputs  - Output file containing decompressed image.           */F /*                                                                  */F /********************************************************************/   #include <stdio.h>   #define TRUE                  1  #define FALSE                 0   F                                     /* pc i/o defines               */F #define O_RDONLY         0x0000     /* open for reading only        */F #define O_BINARY         0x8000     /* file mode is binary          */  F                                     /* vax i/o defines              */F #define RECORD_TYPE      "rfm=fix"  /* VAX fixed length output      */F #define CTX              "ctx=bin"  /* no translation of \n         */F #define FOP          "fop=cif,sup"  /* file processing ops          */   typedef struct leaf    {     struct leaf *right;    short int dn;    struct leaf *left; 	   } NODE;   J /*************************************************************************F  Declare the tree pointer. This pointer will hold the root of the tree@  once the tree is created by the accompanying routine huff_tree.K **************************************************************************/      NODE *tree;   F /* subroutine definitions                                           */    void               pds_labels();! void               fits_labels(); " void               vicar_labels(); void               no_labels();   int                check_host(); int                get_files();   void               open_files(); long               swap_long();   void               decompress(); void               decmpinit();  void               free_tree();  long atol();  F /* global variables                                                 */   int                infile; FILE               *outfile;* char               inname[80],outname[80];! int                output_format; + int                record_bytes, max_lines; * int                line_samples, fits_pad;6 long               label_checksum = 0L, checksum = 0L;   main(argc,argv)   
 int  argc; char **argv;   { - unsigned char          ibuf[2048],obuf[2048];  unsigned char blank=32; - short         host,length,total_bytes,line,i; & long          x,long_length,hist[511]; int           count;  G /*********************************************************************/ G /*                                                                   */ G /* get host information and input and output files                   */ G /*                                                                   */ G /*********************************************************************/       strcpy(inname,"   ");      strcpy(outname,"   ");     output_format = 0;   G    if (argc == 1);                     /* prompt user for parameters */ <    else if (argc == 2 && (strncmp(argv[1],"help",4) == 0 || ;                           strncmp(argv[1],"HELP",4) == 0 || :                           strncmp(argv[1],"?",1)    == 0))      {K       printf("PDS Image Decompression Program.  Command line format:\n\n"); :       printf("VDCOMP [infile] [outfile] [format code]\n");I       printf("   infile        - name of compressed image file.     \n"); I       printf("   outfile       - name of uncompressed output file.  \n"); L       printf("   output format - selected from the following list:  \n");   L       printf("                                                      \n");   L       printf("     1  SFDU/PDS format [DEFAULT].                    \n");   L       printf("     2  FITS format.                                  \n");   L       printf("     3  VICAR format.                                 \n");   L       printf("     4  Unlabelled binary array.                    \n\n");          exit(1);      }      else       {       strcpy(inname,argv[1]);   .       if (argc >= 3) strcpy(outname,argv[2]); '       if (argc == 3) output_format = 1; :       if (argc == 4) sscanf(argv[3],"%d",&output_format);       }    host = check_host(); 7    host = get_files(host); /* may change host if VAX */   G /*********************************************************************/ G /*                                                                   */ G /* read and edit compressed file labels                              */ G /*                                                                   */ G /*********************************************************************/       switch (output_format)       {         case 1: pds_labels(host);                break; !        case 2: fits_labels(host);                 break; "        case 3: vicar_labels(host);                break;         case 4: no_labels(host);       }  @    if (record_bytes == 836)  /* set up values for image sizes */      {       max_lines    =  800;       fits_pad     = 2240;       line_samples =  800;      }    else       {#       max_lines    = 1056;                 fits_pad     = 1536;       line_samples = 1204;      }G /*********************************************************************/ G /*                                                                   */ G /* process the image histogram                                       */ G /*                                                                   */ G /*********************************************************************/   D /* need to know record_bytes,hist_count,hist_item_type,item_count.*/    total_bytes = 0; (    length = read_var((char *)hist,host);&    total_bytes = total_bytes + length;  F    if (record_bytes == 836) /* read one more time for Voyager image */      {8       length = read_var((char *)hist+record_bytes,host);)       total_bytes = total_bytes + length;       }  G    if (host == 2 || host == 5)             /* If non-byte swapped    */ G      for (i=0;i<256;i++)                   /* host, swap bytes in    */ G        hist[i] = swap_long(hist[i]);       /* the output histogram   */       if (output_format == 1)      {        if (record_bytes == 836) 
          {:           fwrite((char *)hist,    record_bytes,1,outfile);=           fwrite((char *)hist+record_bytes,length,1,outfile); 
          }        else 
          {2           fwrite((char *)hist,    1024,1,outfile);           total_bytes = 1024; 
          }@       /*  pad out the histogram to a multiple of record bytes */       if (record_bytes == 836)F         for (i=total_bytes;i<record_bytes*2;i++) fputc(blank,outfile);
       elseD         for (i=total_bytes;i<record_bytes;i++) fputc(blank,outfile);      }G /*********************************************************************/ G /*                                                                   */ G /* process the encoding histogram                                    */ G /* don't have to byte-swap because DECOMP.C does it for us           */ G /*                                                                   */ G /*********************************************************************/    if (record_bytes == 836)     { *      length = read_var((char *)hist,host);.      length = read_var((char *)hist+836,host);/      length = read_var((char *)hist+1672,host);      }    else     { *      length = read_var((char *)hist,host);/      length = read_var((char *)hist+1204,host);      }   G /*********************************************************************/ G /*                                                                   */ G /* process the engineering summary                                   */ G /*                                                                   */ G /*********************************************************************/       total_bytes = 0;      length = read_var(ibuf,host);      if (output_format == 1)      {$       fwrite(ibuf,length,1,outfile);)       total_bytes = total_bytes + length;   <       /*  pad out engineering to multiple of record_bytes */B       for (i=total_bytes;i<record_bytes;i++) fputc(blank,outfile);      }G /*********************************************************************/ G /*                                                                   */ G /* process the line header table                                     */ G /*                                                                   */ G /*********************************************************************/      if (record_bytes == 1204)     {     long_length = 0L;      for (i=0;i<1056;i++)       { $        length = read_var(ibuf,host);        if (output_format == 1)
          {(           fwrite(ibuf,length,1,outfile);-           long_length = long_length + length; 
          }       } :     /*  pad out engineering to multiple of record_bytes */     if (output_format == 1) ?       for (x=long_length;x<1204L*55L;x++) fputc(blank,outfile);     }G /*********************************************************************/ G /*                                                                   */ G /* initialize the decompression                                      */ G /*                                                                   */ G /*********************************************************************/   6     printf("\nInitializing decompression routine..."); 	decmpinit(hist);   G /*********************************************************************/ G /*                                                                   */ G /* decompress the image                                              */ G /*                                                                   */ G /*********************************************************************/   # 	printf("\nDecompressing data...");      line=0;      do       { $        length = read_var(ibuf,host);        if (length <= 0) break;"        long_length = (long)length;        line += 1; :        decompress(ibuf, obuf,&long_length, &record_bytes);        if (output_format == 1)
          {6           count = fwrite(obuf,record_bytes,1,outfile);           if (count != 1)              { G              printf("\nError writing output file.  Aborting program.");*M              printf("\nCheck disk space or for duplicate file name on VAX.");g              exit(1);              } 
          }        else 
          {K           count = fwrite(obuf,line_samples,1,outfile); /* VICAR/FITS/etc */            if (count != 1)              {eG              printf("\nError writing output file.  Aborting program.");iM              printf("\nCheck disk space or for duplicate file name on VAX.");               exit(1);              } 
          }  =        if (record_bytes == 1204) /* do checksum for viking */ @          for (i=0;i<record_bytes;i++) checksum += (long)obuf[i];  6        if (line % 100 == 0) printf("\n line %d",line);/       } while (length > 0 && line < max_lines);,  @       if  (record_bytes == 1204) /* print checksum for viking */G       printf("\n Image label checksum = %ld computed checksum = %ld\n", &              label_checksum,checksum);  /  /*  pad out FITS file to a multiple of 2880 */*  if (output_format == 2)1    for (i=0;i<fits_pad;i++) fputc(blank,outfile);     printf("\n");  free_tree(&long_length);o  close(infile);   fclose(outfile);  }   G /*********************************************************************//G /*                                                                   */ G /* subroutine get_files - get input filenames and open               */*G /*                                                                   */ G /*********************************************************************/    int get_files(host)0	 int host;    {  short   shortint;      if (inname[0] == ' ')      { 9      printf("\nEnter name of file to be decompressed: ");       gets (inname);      }    if (host == 1 | host == 2)     { :      if ((infile = open(inname,O_RDONLY | O_BINARY)) <= 0)        {7         printf("\ncan't open input file: %s\n",inname);          exit(1);        }     }r!   else if (host == 3 | host == 5)      {i/      if ((infile = open(inname,O_RDONLY)) <= 0)         {7         printf("\ncan't open input file: %s\n",inname);          exit(1);        }  D   /****************************************************************/D   /* If we are on a vax see if the file is in var length format.  */D   /* This logic is in here in case the vax file has been stored   */D   /* in fixed or undefined format.  This might be necessary since */D   /* vax variable length files can't be moved to other computer   */D   /* systems with standard comm programs (kermit, for example).   */D   /****************************************************************/        if (host == 3)         {!         read(infile,&shortint,2); *         if (shortint > 0 && shortint < 80)           { G            host = 4;              /* change host to 4                */ =            printf("This is not a VAX variable length file.");*           }*;         else printf("This is a VAX variable length file."); G         lseek(infile,0,0);        /* reposition to beginning of file */         }     }      if (output_format == 0)    do     { A      printf("\nEnter a number for the output format desired:\n"); (      printf("\n  1.  SFDU/PDS format.");$      printf("\n  2.  FITS format.");%      printf("\n  3.  VICAR format."); 2      printf("\n  4.  Unlabelled binary array.\n");(      printf("\n  Enter format number:");      gets(inname);"      output_format = atoi(inname);5     } while (output_format < 1 || output_format > 4);      if (outname[0] == ' ')     { :      printf("\nEnter name of uncompressed output file: ");      gets (outname);     }      return(host);  }   G /*********************************************************************/VG /*                                                                   */lG /* subroutine open_files - open the output file after we get         */ G /*   its record size by reading the input file labels.               */eG /*                                                                   */aG /*********************************************************************/    void open_files(host) 
 int *host;   {/  -   if (*host == 1 || *host == 2 || *host == 5)      { /      if ((outfile = fopen(outname,"wb"))==NULL)T        {9         printf("\ncan't open output file: %s\n",outname);          exit(1);        }     } $   else if (*host == 3 || *host == 4)     {D?      if (output_format == 1)      /* write PDS format blocks */t        {          if (record_bytes == 836)           { *            if ((outfile=fopen(outname,"w",D                               "mrs=836",FOP,CTX,RECORD_TYPE))==NULL)              {?               printf("\ncan't open output file: %s\n",outname);*               exit(1);              }           }          else           {o*            if ((outfile=fopen(outname,"w",E                               "mrs=1204",FOP,CTX,RECORD_TYPE))==NULL)               {?               printf("\ncan't open output file: %s\n",outname);                exit(1);              }           }e        }@      else if (output_format == 2) /* write FITS format blocks */        {'         if ((outfile=fopen(outname,"w", B                            "mrs=2880",FOP,CTX,RECORD_TYPE))==NULL)
          {;           printf("\ncan't open output file: %s\n",outname);            exit(1);
          }        }B      else                         /* write fixed length records */        {          if (record_bytes == 836)           { *            if ((outfile=fopen(outname,"w",D                               "mrs=800",FOP,CTX,RECORD_TYPE))==NULL)              {?               printf("\ncan't open output file: %s\n",outname);o               exit(1);              }           }d         else           {t*            if ((outfile=fopen(outname,"w",E                               "mrs=1204",FOP,CTX,RECORD_TYPE))==NULL)               {?               printf("\ncan't open output file: %s\n",outname);o               exit(1);              }           }M        }     }2 }   G /*********************************************************************/ G /*                                                                   */oG /* subroutine pds_labels - edit PDS labels and write to output file  */ G /*                                                                   */eG /*********************************************************************/    void pds_labels(host) 	 int host;*   {*' char          outstring[80],ibuf[2048];*# unsigned char cr=13,lf=10,blank=32; - short         length,nlen,total_bytes,line,i;S     total_bytes = 0; do   {      length = read_var(ibuf,host);    ibuf[length]=NULL;   F   /******************************************************************/F   /*  edit labels which need to be changed                          */F   /******************************************************************/  <    if      ((i = strncmp(ibuf,"NJPL1I00PDS1",12))     == 0);<    else if ((i = strncmp(ibuf,"CCSD3ZF00001",12))     == 0);<    else if ((i = strncmp(ibuf,"/*          FILE",16)) == 0);<    else if ((i = strncmp(ibuf,"RECORD_TYPE",11))      == 0);F    /*****************************************************************/F    /* don't write any of these labels out until we get the record   */F    /* bytes parameter.                                              */F    /*****************************************************************/7    else if ((i = strncmp(ibuf,"RECORD_BYTES",12)) == 0)*F    /*****************************************************************/F    /* get the record_bytes value                                    */F    /*****************************************************************/      {)       sscanf(ibuf+35,"%d",&record_bytes); 3       if (record_bytes != 836) record_bytes = 1204;l       open_files(&host);J       /* now we can write out the SFDU, comment and Record Type labels. */       if (record_bytes == 836)U         fwrite("CCSD3ZF0000100000001NJPL3IF0PDS200000001 = SFDU_LABEL",53,1,outfile); 
       else[         fwrite("CCSD3ZF0000100000001NJPL3IF0PDS200000001 = SFDU_LABEL",53,1,outfile);      h$       fprintf(outfile,"%c%c",cr,lf);I       fwrite("/*          FILE FORMAT AND LENGTH */",37,1,outfile);      x$       fprintf(outfile,"%c%c",cr,lf);M       fwrite("RECORD_TYPE                      = FIXED_LENGTH",47,1,outfile);a$       fprintf(outfile,"%c%c",cr,lf);8       /* fix record_bytes parameter for Viking images */7       if (record_bytes == 1204) strcpy(ibuf+35,"1204");y$       fwrite(ibuf,length,1,outfile);$       fprintf(outfile,"%c%c",cr,lf);8       total_bytes = total_bytes + length + 57 + 39 + 49;      }  7    else if ((i = strncmp(ibuf,"FILE_RECORDS",12)) == 0) F    /*****************************************************************/F    /* change the file_records count                                 */F    /*****************************************************************/      {5       if (record_bytes == 836) strcpy(ibuf+35,"806");s6       else                     strcpy(ibuf+35,"1115");$       fwrite(ibuf,length,1,outfile);$       fprintf(outfile,"%c%c",cr,lf);-       total_bytes = total_bytes + length + 2;0      }8    else if ((i = strncmp(ibuf,"LABEL_RECORDS",13)) == 0)F    /*****************************************************************/F    /* change the label_records count from 56 to 3                   */F    /*****************************************************************/      {3       if (record_bytes == 836) strcpy(ibuf+35,"3");n3       else                     strcpy(ibuf+35,"2");r       length -= 1;$       fwrite(ibuf,length,1,outfile);$       fprintf(outfile,"%c%c",cr,lf);-       total_bytes = total_bytes + length + 2;       };    else if ((i = strncmp(ibuf,"^IMAGE_HISTOGRAM",16)) == 0)SF    /*****************************************************************/F    /* change the location pointer of image_histogram to record 4    */F    /*****************************************************************/      {3       if (record_bytes == 836) strcpy(ibuf+35,"4"); 3       else                     strcpy(ibuf+35,"3");        length -= 1;$       fwrite(ibuf,length,1,outfile);$       fprintf(outfile,"%c%c",cr,lf);-       total_bytes = total_bytes + length + 2;n      }@    else if ((i = strncmp(ibuf,"^ENCODING_HISTOGRAM)",19)) == 0);F    /*****************************************************************/F    /* delete the encoding_histogram location pointer                */F    /*****************************************************************/=    else if ((i = strncmp(ibuf,"^ENGINEERING_TABLE",18)) == 0) F    /*****************************************************************/F    /* change the location pointer of engineering_summary to record 6*/F    /*****************************************************************/      {3       if (record_bytes == 836) strcpy(ibuf+35,"6"); 3       else                     strcpy(ibuf+35,"4");t       length -= 1;$       fwrite(ibuf,length,1,outfile);$       fprintf(outfile,"%c%c",cr,lf);-       total_bytes = total_bytes + length + 2;{      }=    else if ((i = strncmp(ibuf,"^LINE_HEADER_TABLE",18)) == 0)mF    /*****************************************************************/F    /* change the location pointer of line header table to record 5  */F    /*****************************************************************/      {       strcpy(ibuf+35,"5");       length -= 1;$       fwrite(ibuf,length,1,outfile);$       fprintf(outfile,"%c%c",cr,lf);-       total_bytes = total_bytes + length + 2;       }  0    else if ((i = strncmp(ibuf,"^IMAGE",6)) == 0)F    /*****************************************************************/F    /* change the location pointer of image to record 7              */F    /*****************************************************************/      {       if (record_bytes == 836) 8	         {           strcpy(ibuf+35,"7");           length=length-1;r	         }a       else r	         {t          strcpy(ibuf+35,"60");          length = length - 2; 	         }|$       fwrite(ibuf,length,1,outfile);$       fprintf(outfile,"%c%c",cr,lf);-       total_bytes = total_bytes + length + 2;       }    else if ((i = strncmp(ibuf,E              "OBJECT                           = ENCODING",43)) == 0) F    /*****************************************************************/F    /* delete the 4 encoding histogram labels                        */F    /*****************************************************************/      {3       for (i=0;i<4;i++)   /* ignore these labels */o	         { &          length = read_var(ibuf,host);	         }       }4    else if ((i = strncmp(ibuf," ENCODING",9)) == 0);F    /*****************************************************************/F    /* delete the encoding type label in the image object            */F    /*****************************************************************/:    else if ((host == 2 || host == 5) && (i = strncmp(ibuf,H              " ITEM_TYPE                       = VAX_INTEGER",46)) == 0)F    /*****************************************************************/F    /* change the record_type value from variable to fixed           */F    /*****************************************************************/      {        strcpy(ibuf+35,"INTEGER");       length = length - 4;$       fwrite(ibuf,length,1,outfile);$       fprintf(outfile,"%c%c",cr,lf);-       total_bytes = total_bytes + length + 2;r      }F    /*****************************************************************/F    /* find the checksum and store in label_checksum                 */F    /*****************************************************************/3    else if ((i = strncmp(ibuf," CHECKSUM",9)) == 0)       {          ibuf[length]   = '\0';e&        label_checksum = atol(ibuf+35);      }F    /*****************************************************************/F    /* if none of above write out the label to the output file       */F    /*****************************************************************/    elseo      {$       fwrite(ibuf,length,1,outfile);$       fprintf(outfile,"%c%c",cr,lf);-       total_bytes = total_bytes + length + 2;n      }F    /*****************************************************************/F    /* test for the end of the PDS labels                            */F    /*****************************************************************/>    if ((i = strncmp(ibuf,"END",3)) == 0 && length == 3) break;   } while (length > 0);   @ /* pad out the labels with blanks to multiple of record_bytes */    if (record_bytes == 836) C      for (i=total_bytes;i<record_bytes*3;i++) fputc(blank,outfile);*    else A    for (i=total_bytes;i<record_bytes*2;i++) fputc(blank,outfile);i }i  G /*********************************************************************/uG /*                                                                   */ ? /* subroutine fits_labels - write FITS header to output file */ G /*                                                                   */tG /*********************************************************************/f   void fits_labels(host)	 int host;*   {*' char          ibuf[2048],outstring[80]; - short         length,nlen,total_bytes,line,i; # unsigned char cr=13,lf=10,blank=32;l   do   {o     length = read_var(ibuf,host);F    /*****************************************************************/F    /* find the checksum and store in label_checksum                 */F    /*****************************************************************/.    if ((i = strncmp(ibuf," CHECKSUM",9)) == 0)      { *        ibuf[length]   = '\0';*&        label_checksum = atol(ibuf+35);      }  7    else if ((i = strncmp(ibuf,"RECORD_BYTES",12)) == 0)mF    /*****************************************************************/F    /* get the record_bytes value                                    */F    /*****************************************************************/      {)       sscanf(ibuf+35,"%d",&record_bytes); 3       if (record_bytes != 836) record_bytes = 1204;       }  F    /*****************************************************************/F    /* read to the end of the PDS labels                             */F    /*****************************************************************/>    if ((i = strncmp(ibuf,"END",3)) == 0 && length == 3) break;   } while (length > 0);i   open_files(&host); total_bytes = 0;   strcpy(outstring,\R "SIMPLE  =                    T                                                "); fwrite(outstring,78,1,outfile);e fprintf(outfile,"%c%c",cr,lf); total_bytes = total_bytes + 80;t   strcpy(outstring,eR "BITPIX  =                    8                                                "); fwrite(outstring,78,1,outfile);a fprintf(outfile,"%c%c",cr,lf); total_bytes = total_bytes + 80;f   strcpy(outstring, R "NAXIS   =                    2                                                "); fwrite(outstring,78,1,outfile);  fprintf(outfile,"%c%c",cr,lf); total_bytes = total_bytes + 80;    if (record_bytes == 836)   strcpy(outstring,,T   "NAXIS1  =                  800                                                "); else   strcpy(outstring,rT   "NAXIS1  =                 1204                                                "); fwrite(outstring,78,1,outfile);s fprintf(outfile,"%c%c",cr,lf); total_bytes = total_bytes + 80;t   if (record_bytes == 836)   strcpy(outstring,tT   "NAXIS2  =                  800                                                "); else   strcpy(outstring,*T   "NAXIS2  =                 1056                                                "); fwrite(outstring,78,1,outfile);  fprintf(outfile,"%c%c",cr,lf); total_bytes = total_bytes + 80;a   strcpy(outstring, R "END                                                                           "); fwrite(outstring,78,1,outfile);* fprintf(outfile,"%c%c",cr,lf); total_bytes = total_bytes + 80;n  A /* pad out the labels with blanks to multiple of 2880 for FITS */ 7    for (i=total_bytes;i<2880;i++) fputc(blank,outfile);) }   G /*********************************************************************/ G /*                                                                   */nG /* subroutine vicar_labels - write vicar labels to output file       */ G /*                                                                   */eG /*********************************************************************/f   void vicar_labels(host) 	 int host;    { ' char          ibuf[2048],outstring[80];*- short         length,nlen,total_bytes,line,i;e# unsigned char cr=13,lf=10,blank=32;e   do   {.     length = read_var(ibuf,host);F    /*****************************************************************/F    /* find the checksum and store in label_checksum                 */F    /*****************************************************************/.    if ((i = strncmp(ibuf," CHECKSUM",9)) == 0)      { *        ibuf[length]   = '\0';*&        label_checksum = atol(ibuf+35);      }  7    else if ((i = strncmp(ibuf,"RECORD_BYTES",12)) == 0)>F    /*****************************************************************/F    /* get the record_bytes value                                    */F    /*****************************************************************/      {)       sscanf(ibuf+35,"%d",&record_bytes);i3       if (record_bytes != 836) record_bytes = 1204;       }  F    /*****************************************************************/F    /* read to the end of the PDS labels                             */F    /*****************************************************************/>    if ((i = strncmp(ibuf,"END",3)) == 0 && length == 3) break;   } while (length > 0);(   open_files(&host); total_bytes = 0;   if (record_bytes == 836)   strcpy(outstring, N   "LBLSIZE=800             FORMAT='BYTE'  TYPE='IMAGE'  BUFSIZ=800  DIM=2  "); else   strcpy(outstring,rN   "LBLSIZE=1204            FORMAT='BYTE'  TYPE='IMAGE'  BUFSIZ=1204 DIM=2  "); fwrite(outstring,72,1,outfile);* total_bytes = total_bytes + 72;*   if (record_bytes == 836)   strcpy(outstring, M   "EOL=0  RECSIZE=800  ORG='BSQ'  NL=800  NS=800  NB=1  N1=0  N2=0  N3=0  ");h else   strcpy(outstring, M   "EOL=0  RECSIZE=1204 ORG='BSQ'  NL=1056 NS=1204 NB=1  N1=0  N2=0  N3=0  ");  total_bytes = total_bytes + 71;  fwrite(outstring,71,1,outfile);  strcpy(outstring,* "N4=0  NBB=0  NLB=0"); fwrite(outstring,18,1,outfile);* fprintf(outfile,"%c%c",cr,lf); total_bytes = total_bytes + 20;   G /* pad out the labels with blanks to multiple of record_bytes        */m    if (record_bytes == 836 )6    for (i=total_bytes;i<800;i++) fputc(blank,outfile);    else ?    for (i=total_bytes;i<record_bytes;i++) fputc(blank,outfile);    }D  G /*********************************************************************/{G /*                                                                   */=G /* subroutine no_labels - read past the pds labels                   */DG /*                                                                   */ G /*********************************************************************/    void no_labels(host)	 int host;    { ' char          ibuf[2048],outstring[80]; - short         length,nlen,total_bytes,line,i;_   do   {L     length = read_var(ibuf,host);F    /*****************************************************************/F    /* find the checksum and store in label_checksum                 */F    /*****************************************************************/.    if ((i = strncmp(ibuf," CHECKSUM",9)) == 0)      { O        ibuf[length]   = '\0'; &        label_checksum = atol(ibuf+35);      }  7    else if ((i = strncmp(ibuf,"RECORD_BYTES",12)) == 0) F    /*****************************************************************/F    /* get the record_bytes value                                    */F    /*****************************************************************/      {)       sscanf(ibuf+35,"%d",&record_bytes); 3       if (record_bytes != 836) record_bytes = 1204;)      }  F    /*****************************************************************/F    /* read to the end of the PDS labels                             */F    /*****************************************************************/>    if ((i = strncmp(ibuf,"END",3)) == 0 && length == 3) break;   } while (length > 0);    open_files(&host);   }   G /*********************************************************************/*G /*                                                                   */ G /* subroutine read_var - read variable length records from input file*/uG /*                                                                   */ G /*********************************************************************/*   read_var(ibuf,host)p char  *ibuf; int   host;* {  int   length,result,nlen;[ char  temp;]F union /* this union is used to swap 16 and 32 bit integers          */   {e    char  ichar[4];    short slen;    long  llen;
   } onion;     switch (host)u     {hF      case 1: /*******************************************************/F              /* IBM PC host                                         */F              /*******************************************************/        length = 0;'        result = read(infile,&length,2);)4        nlen =   read(infile,ibuf,length+(length%2));        return (length);e  F      case 2: /*******************************************************/F              /* Macintosh host                                      */F              /*******************************************************/        length = 0;+        result = read(infile,onion.ichar,2);eF        /*     byte swap the length field                            */        temp   = onion.ichar[0];*%        onion.ichar[0]=onion.ichar[1];c        onion.ichar[1]=temp;=F        length = onion.slen;       /* left out of earlier versions   */4        nlen =   read(infile,ibuf,length+(length%2));        return (length);   F      case 3: /*******************************************************/F              /* VAX host with variable length support               */F              /*******************************************************/8        length = read(infile,ibuf,2048/* upper bound */);        return (length);=  F      case 4: /*******************************************************/F              /* VAX host, but not a variable length file            */F              /*******************************************************/        length = 0;'        result = read(infile,&length,2);N4        nlen =   read(infile,ibuf,length+(length%2));  F        /* check to see if we crossed a vax record boundary          */        while (nlen < length)?          nlen += read(infile,ibuf+nlen,length+(length%2)-nlen);e        return (length);   F      case 5: /*******************************************************/F              /* Unix workstation host (non-byte-swapped 32 bit host)*/F              /*******************************************************/        length = 0;+        result = read(infile,onion.ichar,2);*F        /*     byte swap the length field                            */        temp   = onion.ichar[0]; %        onion.ichar[0]=onion.ichar[1];*        onion.ichar[1]=temp;*        length = onion.slen; 4        nlen =   read(infile,ibuf,length+(length%2));        return (length);      }( }f  G /*********************************************************************/%G /*                                                                   */eG /* subroutine check_host - find out what kind of machine we are on   */*G /*                                                                   */lG /*********************************************************************/*   int check_host() {*B /*  This subroutine checks the attributes of the host computer and     returns a host code number.  */ char hostname[80];   int swap,host,bits,var;- union    {w    char  ichar[2];    short ilen;
   } onion;    if (sizeof(var) == 4) bits = 32;                   else bits = 16;   onion.ichar[0] = 1;s onion.ichar[1] = 0;I  ! if (onion.ilen == 1) swap = TRUE;*" else                 swap = FALSE;   if (bits == 16 && swap == TRUE)e   {t    host = 1; /* IBM PC host  */     strcpy(hostname,*I           "Host 1 - 16 bit integers with swapping, no var len support.");    }f    if (bits == 16 && swap == FALSE)   {)0    host = 2; /* Non byte swapped 16 bit host  */    strcpy(hostname,-L           "Host 2 - 16 bit integers without swapping, no var len support.");   }    if (bits == 32 && swap == TRUE)g3  { host = 3; /* VAX host with var length support */O    strcpy(hostname, 7           "Host 3,4 - 32 bit integers with swapping.");*  }    if (bits == 32 && swap == FALSE)   {n%    host = 5; /* OTHER 32-bit host  */     strcpy(hostname,*L           "Host 5 - 32 bit integers without swapping, no var len support.");   }i   printf("%s\n",hostname); return(host);* }*  F long swap_long(inval)  /* swap 4 byte integer                       */ long inval;  {nF union /* this union is used to swap 16 and 32 bit integers          */   {*    char  ichar[4];    short slen;    long  llen;
   } onion;   char   temp;  F   /* byte swap the input field                                      */   onion.llen   = inval;w   temp   = onion.ichar[0];    onion.ichar[0]=onion.ichar[3];   onion.ichar[3]=temp;   temp   = onion.ichar[1];    onion.ichar[1]=onion.ichar[2];   onion.ichar[2]=temp;   return (onion.llen); }*  $  void decompress(ibuf,obuf,nin,nout)M /****************************************************************************eM *_TITLE decompress - decompresses image lines stored in compressed format   **N *_ARGS  TYPE       NAME      I/O        DESCRIPTION                         */N         char       *ibuf;  /* I         Compressed data buffer              */N         char       *obuf;  /* O         Decompressed image line             */N         long int   *nin;   /* I         Number of bytes on input buffer     */N         long int   *nout;  /* I         Number of bytes in output buffer    */     {*(  /* The external root pointer to tree */     extern NODE *tree;  1  /* Declare functions called from this routine */p     void dcmprs();  J /*************************************************************************D   This routine is fairly simple as it's only function is to call the   routine dcmprs.oK **************************************************************************/e  $     dcmprs(ibuf,obuf,nin,nout,tree);       return;,   }    void decmpinit(hist)L /***************************************************************************L *_TITLE decmpinit - initializes the Huffman tree                           *M *_ARGS  TYPE       NAME      I/O        DESCRIPTION                        */*M         long int   *hist;  /* I         First-difference histogram.        */s   { =   extern NODE *tree;          /* Huffman tree root pointer */   ;   /* Specify the calling function to initialize the tree */    NODE *huff_tree();  M /****************************************************************************b/   Simply call the huff_tree routine and return.*N *****************************************************************************/     tree = huff_tree(hist);c  	   return;   }   NODE *huff_tree(hist) M /*****************************************************************************M *_TITLE huff_tree - constructs the Huffman tree; returns pointer to root    *eN *_ARGS  TYPE          NAME        I/O   DESCRIPTION                         */N         long int     *hist;     /* I    First difference histogram          */     {    /*  Local variables used */e@     long int freq_list[512];      /* Histogram frequency list */=     NODE **node_list;             /* DN pointer array list */*  >     register long int *fp;        /* Frequency list pointer */9     register NODE **np;           /* Node list pointer */*  P     register long int num_freq;   /* Number non-zero frequencies in histogram */>     long int sum;                 /* Sum of all frequencies */  E     register short int num_nodes; /* Counter for DN initialization */*=     register short int cnt;       /* Miscellaneous counter */n  7     short int znull = -1;         /* Null node value */   >     register NODE *temp;          /* Temporary node pointer */     /* Functions called */     void sort_freq();o     NODE *new_node();(     char *malloc();;  L /***************************************************************************K   Allocate the array of nodes from memory and initialize these with numbershE   corresponding with the frequency list.  There are only 511 possible*G   permutations of first difference histograms.  There are 512 allocated"(   here to adhere to the FORTRAN version.M ****************************************************************************/e      fp = freq_list;2    node_list = (NODE **) malloc(sizeof(temp)*512);    if (node_list == NULL))     {e0       printf("\nOut of memory in huff_tree!\n");       exit(1);     }     np = node_list;  3    for (num_nodes=1, cnt=512 ; cnt-- ; num_nodes++)*      {K /**************************************************************************oG     The following code has been added to standardize the VAX byte order G     for the "long int" type.  This code is intended to make the routine*'     as machine independant as possible.*L ***************************************************************************/5         unsigned char *cp = (unsigned char *) hist++;_         unsigned long int j;         short int i;6         for (i=4 ; --i >= 0 ; j = (j << 8) | *(cp+i));   /* Now make the assignment */*         *fp++ = j;#         temp = new_node(num_nodes);          *np++ = temp;       }  G      (*--fp) = 0;         /* Ensure the last element is zeroed out.  */*  L /***************************************************************************E   Now, sort the frequency list and eliminate all frequencies of zero.eM ****************************************************************************/*     num_freq = 512;**   sort_freq(freq_list,node_list,num_freq);     fp = freq_list;    np = node_list;   I   for (num_freq=512 ; (*fp) == 0 && (num_freq) ; fp++, np++, num_freq--);*  L /***************************************************************************H   Now create the tree.  Note that if there is only one difference value,H   it is returned as the root.  On each interation, a new node is createdH   and the least frequently occurring difference is assigned to the rightE   pointer and the next least frequency to the left pointer.  The node E   assigned to the left pointer now becomes the combination of the two;A   nodes and it's frequency is the sum of the two combining nodes. M ****************************************************************************/,  (   for (temp=(*np) ; (num_freq--) > 1 ; )     {y         temp = new_node(znull);y         temp->right = (*np++);         temp->left = (*np);          *np = temp;           *(fp+1) = *(fp+1) + *fp;         *fp++ = 0;"         sort_freq(fp,np,num_freq);     }a     return temp;  }   NODE *new_node(value)=M /****************************************************************************eM *_TITLE new_node - allocates a NODE structure and returns a pointer to it   *_N *_ARGS  TYPE        NAME        I/O     DESCRIPTION                         */N         short int   value;    /* I      Value to assign to DN field         */     {t9     NODE *temp;         /* Pointer to the memory block */   8   char *malloc();       /* Memory allocation function */  L /***************************************************************************/   Allocate the memory and intialize the fields.NM ****************************************************************************/;  '   temp = (NODE *) malloc(sizeof(NODE));      if (temp != NULL)      {        temp->right = NULL;        temp->dn = value;i       temp->left = NULL;     }l   else     {;0        printf("\nOut of memory in new_node!\n");        exit(1);      }       return temp;    }   -  void sort_freq(freq_list,node_list,num_freq)tM /****************************************************************************eM *_TITLE sort_freq - sorts frequency and node lists in increasing freq. order* N *_ARGS  TYPE       NAME            I/O  DESCRIPTION                         */N         long int   *freq_list;   /* I   Pointer to frequency list           */N         NODE       **node_list;  /* I   Pointer to array of node pointers   */N         long int   num_freq;     /* I   Number of values in freq list       */     {      /* Local Variables */*D     register long int *i;       /* primary pointer into freq_list */F     register long int *j;       /* secondary pointer into freq_list */  B     register NODE **k;          /* primary pointer to node_list */F     register NODE **l;          /* secondary pointer into node_list */  E     long int temp1;             /* temporary storage for freq_list */*E     NODE *temp2;                /* temporary storage for node_list */   <     register long int cnt;      /* count of list elements */  I /************************************************************************ D   Save the current element - starting with the second - in temporaryB   storage.  Compare with all elements in first part of list movingB   each up one element until the element is larger.  Insert current    element at this point in list.J *************************************************************************/  J    if (num_freq <= 0) return;      /* If no elements or invalid, return */  L    for (i=freq_list, k=node_list, cnt=num_freq ; --cnt ; *j=temp1, *l=temp2)      {         temp1 = *(++i);*         temp2 = *(++k);*  /         for (j = i, l = k ;  *(j-1) > temp1 ; )            {              *j = *(j-1);             *l = *(l-1);             j--;             l--;'             if ( j <= freq_list) break;&           }         }	   return;n   }   %  void dcmprs(ibuf,obuf,nin,nout,root) M /**************************************************************************** M *_TITLE dcmprs - decompresses Huffman coded compressed image lines          *rN *_ARGS  TYPE       NAME       I/O       DESCRIPTION                         */N         char       *ibuf;   /* I        Compressed data buffer              */N         char       *obuf;   /* O        Decompressed image line             */N         long int   *nin;    /* I        Number of bytes on input buffer     */N         long int   *nout;   /* I        Number of bytes in output buffer    */N         NODE       *root;   /* I        Huffman coded tree                  */     {0     /* Local Variables */gG     register NODE *ptr = root;        /* pointer to position in tree */eA     register unsigned char test;      /* test byte for bit set */_A     register unsigned char idn;       /* input compressed byte */e  F     register char odn;                /* last dn value decompressed */  C     char *ilim = ibuf + *nin;         /* end of compressed bytes */*@     char *olim = obuf + *nout;        /* end of output buffer */  K /************************************************************************** J   Check for valid input values for nin, nout and make initial assignments.L ***************************************************************************/  #     if (ilim > ibuf && olim > obuf)*        odn = *obuf++ = *ibuf++;o     else        {7            printf("\nInvalid byte count in dcmprs!\n");e            exit(1);_        }  K /***************************************************************************D   Decompress the input buffer.  Assign the first byte to the workingG   variable, idn.  An arithmatic and (&) is performed using the variable*D   'test' that is bit shifted to the right.  If the result is 0, then   go to right else go to left.L ***************************************************************************/  5     for (idn=(*ibuf) ; ibuf < ilim  ; idn =(*++ibuf))*      {+         for (test=0x80 ; test ; test >>= 1)*            {8             ptr = (test & idn) ? ptr->left : ptr->right;               if (ptr->dn != -1)               {*)                 if (obuf >= olim) return;s%                 odn -= ptr->dn + 256;                  *obuf++ = odn;                 ptr = root;                }*           }*      }
    return;   }*   void free_tree(nfreed)M /*****************************************************************************M *_TITLE free_tree - free memory of all allocated nodes                      *"N *_ARGS  TYPE       NAME       I/O        DESCRIPTION                        */M         long int   *nfreed;  /* O        Return of total count of nodes     **N *                                        freed.                             */   /*M *_DESCR This routine is supplied to the programmer to free up all the       * M *       allocated memory required to build the huffman tree.  The count     **M *       of the nodes freed is returned in the parameter 'nfreed'.  The      *hM *       purpose of the routine is so if the user wishes to decompress more  **M *       than one file per run, the program will not keep allocating new     *iM *       memory without first deallocating all previous nodes associated     *hM *       with the previous file decompression.                               *   M *_HIST  16-AUG-89 Kris Becker   USGS, Flagstaff Original Version            **M *_END                                                                       * M ****************************************************************************/l   {% 	long int total_free = 0;)  8 	extern NODE *tree;      /* Huffman tree root pointer */  + /* Specify the function to free the tree */t 	long int free_node();M /*****************************************************************************:   Simply call the free_node routine and return the result.N *****************************************************************************/  & 	*nfreed = free_node(tree,total_free);   	return; }h  $ long int free_node(pnode,total_free)L /***************************************************************************9 *_TITLE free_node - deallocates an allocated NODE pointer;M *_ARGS  TYPE     NAME          I/O   DESCRIPTION                           */*M         NODE     *pnode;       /* I  Pointer to node to free               */ M         long int total_free;   /* I  Total number of freed nodes           */*   /*L *_DESCR  free_node will check both right and left pointers of a node       *L *        and then free the current node using the free() C utility.        *L *        Note that all nodes attached to the node via right or left        *L *        pointers area also freed, so be sure that this is the desired     *L *        result when calling this routine.                                 *  L *        This routine is supplied to allow successive calls to the         *L *        decmpinit routine.  It will free up the memory allocated          *L *        by previous calls to the decmpinit routine.  The call to free     *L *        a previous huffman tree is:  total = free_node(tree,(long) 0);    *L *        This call must be done by the programmer application routine      *L *        and is not done by any of these routines.                         *M *_HIST   16-AUG-89  Kris Becker U.S.G.S  Flagstaff Original Version        */  { 0 	if (pnode == (NODE *) NULL) return(total_free); 	[# 	if (pnode->right != (NODE *) NULL)a2 		total_free = free_node(pnode->right,total_free);" 	if (pnode->left != (NODE *) NULL)1 		total_free = free_node(pnode->left,total_free);n   	free((char *) pnode); 	return(total_free + 1); }*  