home *** CD-ROM | disk | FTP | other *** search
/ Voyagers to the Outer Planets 2: Uranus / VoyagestotheOuterPlanetsVol2.cdr / software / cdcomp.c < prev    next >
C/C++ Source or Header  |  1988-09-14  |  41KB  |  1,078 lines

  1. /********************************************************************/
  2. /*  Voyager Image Decompression Program - C Version for PC, VAX,    */
  3. /*  and UNIX systems.                                               */
  4. /*                                                                  */
  5. /*  Decompresses images using Kris Becker's subroutine DECOMP.C     */
  6. /*  which is included in this program in a shortened version.       */
  7. /*                                                                  */
  8. /*  Reads a variable length compressed VOYAGER image and outputs a  */
  9. /*  fixed length uncompressed image file in PDS format with         */
  10. /*  labels, image histogram, engineering table and 800 lines of     */
  11. /*  836 bytes (800 samples, 36 engineering bytes); or an 800 by     */
  12. /*  800 array with FITS, VICAR or no labels.  If used on a non-     */
  13. /*  byte-swapped machine the image histogram is un-swapped.         */
  14. /*                                                                  */
  15. /*  Use the following commands to compile and link to produce an    */
  16. /*  executable file:                                                */
  17. /*                                                                  */
  18. /*  On an IBM PC (using Microsoft C Version 5.x)                    */
  19. /*                                                                  */
  20. /*    cl /c cdcomp.c                                                */
  21. /*    link  cdcomp/stack:10000;                                     */
  22. /*                                                                  */
  23. /*  On a VAX:                                                       */
  24. /*                                                                  */
  25. /*    cc   cdcomp                                                   */
  26. /*    link cdcomp                                                   */
  27. /*                                                                  */
  28. /*  On a Unix host (Sun, Masscomp)                                  */
  29. /*                                                                  */
  30. /*    cc -o cdcomp cdcomp.c                                         */
  31. /*                                                                  */
  32. /* LIMS                                                             */
  33. /*  This program has been tested on a VAX 780 (VMS 4.6), SUN        */
  34. /*  Workstation (UNIX 4.2, release 3.4), and an IBM PC              */
  35. /*  (MICROSOFT 5.1 compiler).  When converting to other             */
  36. /*  systems, check for portability conflicts.                       */
  37. /*                                                                  */
  38. /* HIST                                                             */
  39. /*  JUL88 C driver to decompress standard Voyager Compressed images */
  40. /*  by Mike Martin 1988/07/30                                       */
  41. /*                                                                  */
  42. /*  Inputs   - Input file to be decompressed.                       */
  43. /*                                                                  */
  44. /*  Outputs  - Output file containing decompressed image.           */
  45. /*                                                                  */
  46. /********************************************************************/
  47.  
  48. #include <stdio.h>
  49.  
  50. #define TRUE                  1
  51. #define FALSE                 0
  52. #define RECORD_BYTES        836
  53.  
  54.                                     /* pc i/o defines               */
  55. #define O_RDONLY         0x0000     /* open for reading only        */
  56. #define O_BINARY         0x8000     /* file mode is binary          */
  57.  
  58.                                     /* vax i/o defines              */
  59. #define RECORD_TYPE      "rfm=fix"  /* VAX fixed length output      */
  60. #define CTX              "ctx=bin"  /* no translation of \n         */
  61. #define FOP          "fop=cif,sup"  /* file processing ops          */
  62.  
  63. typedef struct leaf
  64.   {
  65.    struct leaf *right;
  66.    short int dn;
  67.    struct leaf *left;
  68.   } NODE;
  69.  
  70. /*************************************************************************
  71.  Declare the tree pointer. This pointer will hold the root of the tree
  72.  once the tree is created by the accompanying routine huff_tree.
  73. **************************************************************************/
  74.  
  75.   NODE *tree;
  76.  
  77. /* subroutine definitions                                           */
  78.  
  79. void               pds_labels();
  80. void               fits_labels();
  81. void               vicar_labels();
  82. void               no_labels();
  83. int                check_host();
  84. int                get_files();
  85. long               swap_long();
  86. void               decompress();
  87. void               decmpinit();
  88.  
  89. /* global variables                                                 */
  90.  
  91. int                infile;
  92. FILE               *outfile;
  93. int                output_format;
  94.  
  95. main()
  96.  
  97. {
  98. char          ibuf[2048],obuf[2048];
  99. unsigned char blank=32;
  100. short         host,length,total_bytes,line,i;
  101. long          long_length,hist[511];
  102. int           out_bytes = RECORD_BYTES;
  103. int           count;
  104.  
  105. /*********************************************************************/
  106. /*                                                                   */
  107. /* get host information and input and output files                   */
  108. /*                                                                   */
  109. /*********************************************************************/
  110.  
  111.    host = check_host();
  112.    host = get_files(host); /* may change host if VAX */
  113.  
  114. /*********************************************************************/
  115. /*                                                                   */
  116. /* read and edit compressed file labels                              */
  117. /*                                                                   */
  118. /*********************************************************************/
  119.  
  120.    switch (output_format)
  121.      {
  122.        case 1: pds_labels(host);
  123.                break;
  124.        case 2: fits_labels(host);
  125.                break;
  126.        case 3: vicar_labels(host);
  127.                break;
  128.        case 4: no_labels(host);
  129.      }
  130. /*********************************************************************/
  131. /*                                                                   */
  132. /* process the image histogram                                       */
  133. /*                                                                   */
  134. /*********************************************************************/
  135.  
  136. /* need to know record_bytes,hist_count,hist_item_type,item_count.*/
  137.    total_bytes = 0;
  138.    length = read_var((char *)hist,host);
  139.    total_bytes = total_bytes + length;
  140.    length = read_var((char *)hist+836,host);
  141.    total_bytes = total_bytes + length;
  142.  
  143.    if (host == 2 || host == 5)             /* If non-byte swapped    */
  144.      for (i=0;i<256;i++)                   /* host, swap bytes in    */
  145.        hist[i] = swap_long(hist[i]);       /* the output histogram   */
  146.  
  147.    if (output_format == 1)
  148.      {
  149.       fwrite((char *)hist,    836,1,outfile);
  150.       fwrite((char *)hist+836,length,1,outfile);
  151.  
  152.       /*  pad out the histogram to a multiple of RECORD_BYTES */
  153.       for (i=total_bytes;i<RECORD_BYTES*2;i++) fputc(blank,outfile);
  154.      }
  155. /*********************************************************************/
  156. /*                                                                   */
  157. /* process the encoding histogram                                    */
  158. /* don't have to byte-swap because DECOMP.C does it for us           */
  159. /*                                                                   */
  160. /*********************************************************************/
  161.  
  162.    length = read_var((char *)hist,host);
  163.    length = read_var((char *)hist+836,host);
  164.    length = read_var((char *)hist+1672,host);
  165.  
  166. /*********************************************************************/
  167. /*                                                                   */
  168. /* process the engineering summary                                   */
  169. /*                                                                   */
  170. /*********************************************************************/
  171.  
  172.    total_bytes = 0;
  173.    length = read_var(ibuf,host);
  174.  
  175.    if (output_format == 1)
  176.      {
  177.       fwrite(ibuf,length,1,outfile);
  178.       total_bytes = total_bytes + length;
  179.  
  180.       /*  pad out engineering to multiple of 836 */
  181.       for (i=total_bytes;i<RECORD_BYTES;i++) fputc(blank,outfile);
  182.      }
  183. /*********************************************************************/
  184. /*                                                                   */
  185. /* initialize the decompression                                      */
  186. /*                                                                   */
  187. /*********************************************************************/
  188.  
  189.     printf("\nInitializing decompression routine...");
  190.     decmpinit(hist);
  191.  
  192. /*********************************************************************/
  193. /*                                                                   */
  194. /* decompress the image                                              */
  195. /*                                                                   */
  196. /*********************************************************************/
  197.  
  198.     printf("\nDecompressing data...");
  199.     line=0;
  200.     do
  201.       {
  202.        length = read_var(ibuf,host);
  203.        if (length <= 0) break;
  204.        long_length = (long)length;
  205.        line += 1;
  206.        decompress(ibuf, obuf,&long_length, &out_bytes);
  207.        if (output_format == 1)
  208.          {
  209.           count = fwrite(obuf,RECORD_BYTES,1,outfile);
  210.           if (count != 1)
  211.             {
  212.              printf("\nError writing output file.  Aborting program.");
  213.              printf("\nCheck disk space or for duplicate file name on VAX.");
  214.              exit(1);
  215.             }
  216.          }
  217.        else fwrite(obuf,800,1,outfile);
  218.  
  219.        if (line % 100 == 0) printf("\n line %d",line);
  220.       } while (length > 0 && line < 800);
  221.  
  222.  /*  pad out FITS file to a multiple of 2880 */
  223.  if (output_format == 2)
  224.    for (i=0;i<2240;i++) fputc(blank,outfile);
  225.  
  226.  printf("\n");
  227.  close(infile);
  228.  fclose(outfile);
  229. }
  230.  
  231. /*********************************************************************/
  232. /*                                                                   */
  233. /* subroutine get_files - get input filenames and open               */
  234. /*                                                                   */
  235. /*********************************************************************/
  236.  
  237. int get_files(host)
  238. int host;
  239.  
  240. {
  241. char    inname[80],outname[80];
  242. short   shortint;
  243.  
  244.   printf("\nEnter name of file to be decompressed: ");
  245.   gets (inname);
  246.   if (host == 1)
  247.     {
  248.      if ((infile = open(inname,O_RDONLY | O_BINARY)) <= 0)
  249.        {
  250.         printf("\ncan't open input file: %s\n",inname);
  251.         exit(1);
  252.        }
  253.     }
  254.   else if (host == 2 | host == 3 | host == 5)
  255.     {
  256.      if ((infile = open(inname,O_RDONLY)) <= 0)
  257.        {
  258.         printf("\ncan't open input file: %s\n",inname);
  259.         exit(1);
  260.        }
  261.  
  262.   /****************************************************************/
  263.   /* If we are on a vax see if the file is in var length format.  */
  264.   /* This logic is in here in case the vax file has been stored   */
  265.   /* in fixed or undefined format.  This might be necessary since */
  266.   /* vax variable length files can't be moved to other computer   */
  267.   /* systems with standard comm programs (kermit, for example).   */
  268.   /****************************************************************/
  269.  
  270.      if (host == 3)
  271.        {
  272.         read(infile,&shortint,2);
  273.         if (shortint > 0 && shortint < 80)
  274.           {
  275.            host = 4;              /* change host to 4                */
  276.            printf("This is not a VAX variable length file.");
  277.           }
  278.         else printf("This is a VAX variable length file.");
  279.         lseek(infile,0,0);        /* reposition to beginning of file */
  280.        }
  281.     }
  282.  
  283.   output_format = 0;
  284.   do
  285.     {
  286.      printf("\nEnter a number for the output format desired:\n");
  287.      printf("\n  1.  SFDU/PDS format.");
  288.      printf("\n  2.  FITS format.");
  289.      printf("\n  3.  VICAR format.");
  290.      printf("\n  4.  Unlabelled binary array.\n");
  291.      printf("\n  Enter format number:");
  292.      gets(inname);
  293.      output_format = atoi(inname);
  294.     } while (output_format < 1 || output_format > 4);
  295.  
  296.   printf("\nEnter name of uncompressed output file: ");
  297.   gets (outname);
  298.  
  299.   if (host == 1 || host == 2 || host == 5)
  300.     {
  301.      if ((outfile = fopen(outname,"wb"))==NULL)
  302.        {
  303.         printf("\ncan't open output file: %s\n",outname);
  304.         exit(1);
  305.        }
  306.     }
  307.   else if (host == 3 || host == 4)
  308.     {
  309.      if (output_format == 1)      /* write PDS format blocks */
  310.        {
  311.         if ((outfile=fopen(outname,"w",
  312.                            "mrs=836",FOP,CTX,RECORD_TYPE))==NULL)
  313.          {
  314.           printf("\ncan't open output file: %s\n",outname);
  315.           exit(1);
  316.          }
  317.        }
  318.      else if (output_format == 2) /* write FITS format blocks */
  319.        {
  320.         if ((outfile=fopen(outname,"w",
  321.                            "mrs=2880",FOP,CTX,RECORD_TYPE))==NULL)
  322.          {
  323.           printf("\ncan't open output file: %s\n",outname);
  324.           exit(1);
  325.          }
  326.        }
  327.      else                         /* write 800 byte records */
  328.        {
  329.         if ((outfile=fopen(outname,"w",
  330.                            "mrs=800",FOP,CTX,RECORD_TYPE))==NULL)
  331.          {
  332.           printf("\ncan't open output file: %s\n",outname);
  333.           exit(1);
  334.          }
  335.        }
  336.     }
  337.  
  338.   return(host);  /* In case its been updated */
  339. }
  340.  
  341. /*********************************************************************/
  342. /*                                                                   */
  343. /* subroutine pds_labels - edit PDS labels and write to output file */
  344. /*                                                                   */
  345. /*********************************************************************/
  346.  
  347. void pds_labels(host)
  348. int host;
  349.  
  350. {
  351. char          outstring[80],ibuf[2048];
  352. unsigned char cr=13,lf=10,blank=32;
  353. short         length,nlen,total_bytes,line,i;
  354.  
  355.  
  356. total_bytes = 0;
  357. do
  358.   {
  359.    length = read_var(ibuf,host);
  360.    ibuf[length]=NULL;
  361.  
  362.   /******************************************************************/
  363.   /*  edit labels which need to be changed                          */
  364.   /******************************************************************/
  365.  
  366.    if      ((i = strncmp(ibuf,"NJPL1I00PDS1",12)) == 0)
  367.    /*****************************************************************/
  368.    /* add the output file length to the sfdu label                  */
  369.    /*****************************************************************/
  370.      {
  371.       strcpy(outstring,ibuf);
  372.       strcpy(outstring+12,"00673816");
  373.       strcpy(outstring+20,ibuf+20);
  374.       fwrite(outstring,length,1,outfile);
  375.       fprintf(outfile,"%c%c",cr,lf);
  376.       total_bytes = total_bytes + length + 2;
  377.      }
  378.    else if ((i = strncmp(ibuf,"RECORD_TYPE",11)) == 0)
  379.    /*****************************************************************/
  380.    /* change the record_type value from variable to fixed           */
  381.    /*****************************************************************/
  382.      {
  383.       strcpy(ibuf+35,"FIXED_LENGTH");
  384.       length = length - 3;
  385.       fwrite(ibuf,length,1,outfile);
  386.       fprintf(outfile,"%c%c",cr,lf);
  387.       total_bytes = total_bytes + length + 2;
  388.      }
  389.    else if ((i = strncmp(ibuf,"FILE_RECORDS",12)) == 0)
  390.    /*****************************************************************/
  391.    /* change the file_records count to 806                          */
  392.    /*****************************************************************/
  393.      {
  394.       strcpy(ibuf+35,"806");
  395.       fwrite(ibuf,length,1,outfile);
  396.       fprintf(outfile,"%c%c",cr,lf);
  397.       total_bytes = total_bytes + length + 2;
  398.      }
  399.    else if ((i = strncmp(ibuf,"LABEL_RECORDS",13)) == 0)
  400.    /*****************************************************************/
  401.   /* change the label_records count from 56 to 3                    */
  402.    /*****************************************************************/
  403.      {
  404.       strcpy(ibuf+35,"3");
  405.       length -= 1;
  406.       fwrite(ibuf,length,1,outfile);
  407.       fprintf(outfile,"%c%c",cr,lf);
  408.       total_bytes = total_bytes + length + 2;
  409.      }
  410.    else if ((i = strncmp(ibuf,"^IMAGE_HISTOGRAM",16)) == 0)
  411.    /*****************************************************************/
  412.    /* change the location pointer of image_histogram to record 4    */
  413.    /*****************************************************************/
  414.      {
  415.       strcpy(ibuf+35,"4");
  416.       length -= 1;
  417.       fwrite(ibuf,length,1,outfile);
  418.       fprintf(outfile,"%c%c",cr,lf);
  419.       total_bytes = total_bytes + length + 2;
  420.      }
  421.    else if ((i = strncmp(ibuf,"^ENCODING_HISTOGRAM)",19)) == 0);
  422.    /*****************************************************************/
  423.    /* delete the encoding_histogram location pointer                */
  424.    /*****************************************************************/
  425.    else if ((i = strncmp(ibuf,"^ENGINEERING_TABLE",18)) == 0)
  426.    /*****************************************************************/
  427.    /* change the location pointer of engineering_summary to record 6*/
  428.    /*****************************************************************/
  429.      {
  430.       strcpy(ibuf+35,"6");
  431.       length -= 1;
  432.       fwrite(ibuf,length,1,outfile);
  433.       fprintf(outfile,"%c%c",cr,lf);
  434.       total_bytes = total_bytes + length + 2;
  435.      }
  436.    else if ((i = strncmp(ibuf,"^IMAGE",6)) == 0)
  437.    /*****************************************************************/
  438.    /* change the location pointer of image to record 7              */
  439.    /*****************************************************************/
  440.      {
  441.       strcpy(ibuf+35,"7");
  442.       length = length -1;
  443.       fwrite(ibuf,length,1,outfile);
  444.       fprintf(outfile,"%c%c",cr,lf);
  445.       total_bytes = total_bytes + length + 2;
  446.      }
  447.    else if ((i = strncmp(ibuf,
  448.              "OBJECT                           = ENCODING",43)) == 0)
  449.    /*****************************************************************/
  450.    /* delete the 4 encoding histogram labels                        */
  451.    /*****************************************************************/
  452.      {
  453.       for (i=0;i<4;i++)   /* ignore these labels */
  454.         {
  455.          length = read_var(ibuf,host);
  456.         }
  457.      }
  458.    else if ((i = strncmp(ibuf," ENCODING",9)) == 0);
  459.    /*****************************************************************/
  460.    /* delete the encoding type label in the image object            */
  461.    /*****************************************************************/
  462.    else if ((host == 2 || host == 5) && (i = strncmp(ibuf,
  463.              " ITEM_TYPE                       = VAX_INTEGER",46)) == 0)
  464.    /*****************************************************************/
  465.    /* change the record_type value from variable to fixed           */
  466.    /*****************************************************************/
  467.      {
  468.       strcpy(ibuf+35,"INTEGER");
  469.       length = length - 4;
  470.       fwrite(ibuf,length,1,outfile);
  471.       fprintf(outfile,"%c%c",cr,lf);
  472.       total_bytes = total_bytes + length + 2;
  473.      }
  474.  
  475.  
  476.  
  477.    /*****************************************************************/
  478.    /* if none of above write out the label to the output file       */
  479.    /*****************************************************************/
  480.    else
  481.      {
  482.       fwrite(ibuf,length,1,outfile);
  483.       fprintf(outfile,"%c%c",cr,lf);
  484.       total_bytes = total_bytes + length + 2;
  485.      }
  486.    /*****************************************************************/
  487.    /* test for the end of the PDS labels                            */
  488.    /*****************************************************************/
  489.    if ((i = strncmp(ibuf,"END",3)) == 0 && length == 3) break;
  490.   } while (length > 0);
  491.  
  492. /* pad out the labels with blanks to multiple of RECORD_BYTES */
  493.    for (i=total_bytes;i<RECORD_BYTES*3;i++) fputc(blank,outfile);
  494. }
  495.  
  496. /*********************************************************************/
  497. /*                                                                   */
  498. /* subroutine fits_labels - write FITS header to output file */
  499. /*                                                                   */
  500. /*********************************************************************/
  501.  
  502. void fits_labels(host)
  503. int host;
  504.  
  505. {
  506. char          ibuf[2048],outstring[80];
  507. unsigned char cr=13,lf=10,blank=32;
  508. short         length,nlen,total_bytes,line,i;
  509.  
  510. do
  511.   {
  512.    length = read_var(ibuf,host);
  513.    /*****************************************************************/
  514.    /* read to the end of the PDS labels                             */
  515.    /*****************************************************************/
  516.    if ((i = strncmp(ibuf,"END",3)) == 0 && length == 3) break;
  517.   } while (length > 0);
  518.  
  519. total_bytes = 0;
  520.  
  521. strcpy(outstring,
  522. "SIMPLE  =                    T                                                ");
  523. fwrite(outstring,78,1,outfile);
  524. fprintf(outfile,"%c%c",cr,lf);
  525. total_bytes = total_bytes + 80;
  526.  
  527. strcpy(outstring,
  528. "BITPIX  =                    8                                                ");
  529. fwrite(outstring,78,1,outfile);
  530. fprintf(outfile,"%c%c",cr,lf);
  531. total_bytes = total_bytes + 80;
  532.  
  533. strcpy(outstring,
  534. "NAXIS   =                    2                                                ");
  535. fwrite(outstring,78,1,outfile);
  536. fprintf(outfile,"%c%c",cr,lf);
  537. total_bytes = total_bytes + 80;
  538.  
  539. strcpy(outstring,
  540. "NAXIS1  =                  800                                                ");
  541. fwrite(outstring,78,1,outfile);
  542. fprintf(outfile,"%c%c",cr,lf);
  543. total_bytes = total_bytes + 80;
  544.  
  545. strcpy(outstring,
  546. "NAXIS2  =                  800                                                ");
  547. fwrite(outstring,78,1,outfile);
  548. fprintf(outfile,"%c%c",cr,lf);
  549. total_bytes = total_bytes + 80;
  550.  
  551. strcpy(outstring,
  552. "END                                                                           ");
  553. fwrite(outstring,78,1,outfile);
  554. fprintf(outfile,"%c%c",cr,lf);
  555. total_bytes = total_bytes + 80;
  556.  
  557. /* pad out the labels with blanks to multiple of RECORD_BYTES */
  558.    for (i=total_bytes;i<2880;i++) fputc(blank,outfile);
  559. }
  560.  
  561. /*********************************************************************/
  562. /*                                                                   */
  563. /* subroutine vicar_labels - write vicar labels to output file       */
  564. /*                                                                   */
  565. /*********************************************************************/
  566.  
  567. void vicar_labels(host)
  568. int host;
  569.  
  570. {
  571. char          ibuf[2048],outstring[80];
  572. unsigned char cr=13,lf=10,blank=32;
  573. short         length,nlen,total_bytes,line,i;
  574.  
  575. do
  576.   {
  577.    length = read_var(ibuf,host);
  578.    /*****************************************************************/
  579.    /* read to the end of the PDS labels                             */
  580.    /*****************************************************************/
  581.    if ((i = strncmp(ibuf,"END",3)) == 0 && length == 3) break;
  582.   } while (length > 0);
  583.  
  584. total_bytes = 0;
  585.  
  586. strcpy(outstring,
  587. "LBLSIZE=800             FORMAT='BYTE'  TYPE='IMAGE'  BUFSIZ=800  DIM=2  ");
  588. fwrite(outstring,72,1,outfile);
  589. total_bytes = total_bytes + 72;
  590. strcpy(outstring,
  591. "EOL=0  RECSIZE=800  ORG='BSQ'  NL=800  NS=800  NB=1  N1=0  N2=0  N3=0  ");
  592. total_bytes = total_bytes + 71;
  593. fwrite(outstring,71,1,outfile);
  594. strcpy(outstring,
  595. "N4=0  NBB=0  NLB=0");
  596. fwrite(outstring,18,1,outfile);
  597. fprintf(outfile,"%c%c",cr,lf);
  598. total_bytes = total_bytes + 20;
  599.  
  600. /* pad out the labels with blanks to multiple of RECORD_BYTES */
  601.    for (i=total_bytes;i<800;i++) fputc(blank,outfile);
  602. }
  603.  
  604. /*********************************************************************/
  605. /*                                                                   */
  606. /* subroutine no_labels - read past the pds labels                   */
  607. /*                                                                   */
  608. /*********************************************************************/
  609.  
  610. void no_labels(host)
  611. int host;
  612.  
  613. {
  614. char          ibuf[2048],outstring[80];
  615. unsigned char cr=13,lf=10,blank=32;
  616. short         length,nlen,total_bytes,line,i;
  617.  
  618. do
  619.   {
  620.    length = read_var(ibuf,host);
  621.    /*****************************************************************/
  622.    /* read to the end of the PDS labels                             */
  623.    /*****************************************************************/
  624.    if ((i = strncmp(ibuf,"END",3)) == 0 && length == 3) break;
  625.   } while (length > 0);
  626.  
  627. }
  628.  
  629.  
  630. /*********************************************************************/
  631. /*                                                                   */
  632. /* subroutine read_var - read variable length records from input file*/
  633. /*                                                                   */
  634. /*********************************************************************/
  635.  
  636. read_var(ibuf,host)
  637. char  *ibuf;
  638. int   host;
  639. {
  640. int   length,result,nlen;
  641. char  temp;
  642. union /* this union is used to swap 16 and 32 bit integers          */
  643.   {
  644.    char  ichar[4];
  645.    short slen;
  646.    long  llen;
  647.   } onion;
  648.  
  649.   switch (host)
  650.     {
  651.      case 1: /*******************************************************/
  652.              /* IBM PC host                                         */
  653.              /*******************************************************/
  654.        length = 0;
  655.        result = read(infile,&length,2);
  656.        nlen =   read(infile,ibuf,length+(1*length%2));
  657.        return (length);
  658.        break;
  659.  
  660.      case 2: /*******************************************************/
  661.              /* non byte swapped 16 bit host                        */
  662.              /*******************************************************/
  663.        length = 0;
  664.        result = read(infile,onion.ichar,2);
  665.        /*     byte swap the length field                            */
  666.        temp   = onion.ichar[0];
  667.        onion.ichar[0]=onion.ichar[1];
  668.        onion.ichar[1]=temp;
  669.        /* printf("length=%04x,result=%d\n",length,result);          */
  670.        nlen =   read(infile,ibuf,length+(1*length%2));
  671.        return (length);
  672.        break;
  673.  
  674.      case 3: /*******************************************************/
  675.              /* VAX host with variable length support               */
  676.              /*******************************************************/
  677.        length = read(infile,ibuf,RECORD_BYTES);
  678.        return (length);
  679.  
  680.      case 4: /*******************************************************/
  681.              /* VAX host, but not a variable length file            */
  682.              /*******************************************************/
  683.        length = 0;
  684.        result = read(infile,&length,2);
  685.        nlen =   read(infile,ibuf,length+(1*length%2));
  686.  
  687.        /* check to see if we crossed a vax record boundary          */
  688.        while (nlen < length)
  689.          nlen += read(infile,ibuf+nlen,length+(1*length%2)-nlen);
  690.        return (length);
  691.        break;
  692.  
  693.      case 5: /*******************************************************/
  694.              /* non byte swapped 32 bit host without var support    */
  695.              /*******************************************************/
  696.        length = 0;
  697.        result = read(infile,onion.ichar,2);
  698.        /*     byte swap the length field                            */
  699.        temp   = onion.ichar[0];
  700.        onion.ichar[0]=onion.ichar[1];
  701.        onion.ichar[1]=temp;
  702.        length = onion.slen;
  703.        /* printf("length=%04x,result=%d\n",length,result); */
  704.        nlen =   read(infile,ibuf,length+(1*length%2));
  705.        return (length);
  706.        break;
  707.     }
  708. }
  709.  
  710. /*********************************************************************/
  711. /*                                                                   */
  712. /* subroutine check_host - find out what kind of machine we are on   */
  713. /*                                                                   */
  714. /*********************************************************************/
  715.  
  716. int check_host()
  717. {
  718. /*  This subroutine checks the attributes of the host computer and
  719.     returns a host code number.
  720. */
  721. char hostname[80];
  722.  
  723. int swap,host,bits,var;
  724. union
  725.   {
  726.    char  ichar[2];
  727.    short ilen;
  728.   } onion;
  729.  
  730. if (sizeof(var) == 4) bits = 32;
  731.                  else bits = 16;
  732.  
  733. onion.ichar[0] = 1;
  734. onion.ichar[1] = 0;
  735.  
  736. if (onion.ilen == 1) swap = TRUE;
  737. else                 swap = FALSE;
  738.  
  739. if (bits == 16 && swap == TRUE)
  740.   {
  741.    host = 1; /* IBM PC host  */
  742.    strcpy(hostname,
  743.           "Type 1 - 16 bit integers with swapping, no var len support.");
  744.   }
  745.  
  746. if (bits == 16 && swap == FALSE)
  747.   {
  748.    host = 2; /* Non byte swapped 16 bit host  */
  749.    strcpy(hostname,
  750.           "Type 2 - 16 bit integers without swapping, no var len support.");
  751.   }
  752.  
  753. if (bits == 32 && swap == TRUE)
  754.  { host = 3; /* VAX host with var length support */
  755.    strcpy(hostname,
  756.           "Type 3,4 - 32 bit integers with swapping.");
  757.  }
  758.  
  759. if (bits == 32 && swap == FALSE)
  760.   {
  761.    host = 5; /* OTHER 32-bit host  */
  762.    strcpy(hostname,
  763.           "Type 5 - 32 bit integers without swapping, no var len support.");
  764.   }
  765.  
  766. printf("%s\n",hostname);
  767. return(host);
  768. }
  769.  
  770. long swap_long(inval)  /* swap 4 byte integer                       */
  771. long inval;
  772. {
  773. union /* this union is used to swap 16 and 32 bit integers          */
  774.   {
  775.    char  ichar[4];
  776.    short slen;
  777.    long  llen;
  778.   } onion;
  779.   char   temp;
  780.  
  781.   /* byte swap the input field                                      */
  782.   onion.llen   = inval;
  783.   temp   = onion.ichar[0];
  784.   onion.ichar[0]=onion.ichar[3];
  785.   onion.ichar[3]=temp;
  786.   temp   = onion.ichar[1];
  787.   onion.ichar[1]=onion.ichar[2];
  788.   onion.ichar[2]=temp;
  789.   return (onion.llen);
  790. }
  791.  
  792.  void decompress(ibuf,obuf,nin,nout)
  793. /****************************************************************************
  794. *_TITLE decompress - decompresses image lines stored in compressed format   *
  795. *_ARGS  TYPE       NAME      I/O        DESCRIPTION                         */
  796.         char       *ibuf;  /* I         Compressed data buffer              */
  797.         char       *obuf;  /* O         Decompressed image line             */
  798.         long int   *nin;   /* I         Number of bytes on input buffer     */
  799.         long int   *nout;  /* I         Number of bytes in output buffer    */
  800.  
  801.   {
  802.  /* The external root pointer to tree */
  803.     extern NODE *tree;
  804.  
  805.  /* Declare functions called from this routine */
  806.     void dcmprs();
  807.  
  808. /*************************************************************************
  809.   This routine is fairly simple as it's only function is to call the
  810.   routine dcmprs.
  811. **************************************************************************/
  812.  
  813.     dcmprs(ibuf,obuf,nin,nout,tree);
  814.  
  815.     return;
  816.   }
  817.  
  818. void decmpinit(hist)
  819. /***************************************************************************
  820. *_TITLE decmpinit - initializes the Huffman tree                           *
  821. *_ARGS  TYPE       NAME      I/O        DESCRIPTION                        */
  822.         long int   *hist;  /* I         First-difference histogram.        */
  823.  
  824. {
  825.   extern NODE *tree;          /* Huffman tree root pointer */
  826.  
  827.   /* Specify the calling function to initialize the tree */
  828.   NODE *huff_tree();
  829.  
  830. /****************************************************************************
  831.   Simply call the huff_tree routine and return.
  832. *****************************************************************************/
  833.  
  834.   tree = huff_tree(hist);
  835.  
  836.   return;
  837.  }
  838.  
  839. NODE *huff_tree(hist)
  840. /****************************************************************************
  841. *_TITLE huff_tree - constructs the Huffman tree; returns pointer to root    *
  842. *_ARGS  TYPE          NAME        I/O   DESCRIPTION                         */
  843.         long int     *hist;     /* I    First difference histogram          */
  844.  
  845.   {
  846.   /*  Local variables used */
  847.     long int freq_list[512];      /* Histogram frequency list */
  848.     NODE **node_list;             /* DN pointer array list */
  849.  
  850.     register long int *fp;        /* Frequency list pointer */
  851.     register NODE **np;           /* Node list pointer */
  852.  
  853.     register long int num_freq;   /* Number non-zero frequencies in histogram */
  854.     long int sum;                 /* Sum of all frequencies */
  855.  
  856.     register short int num_nodes; /* Counter for DN initialization */
  857.     register short int cnt;       /* Miscellaneous counter */
  858.  
  859.     short int znull = -1;         /* Null node value */
  860.  
  861.     register NODE *temp;          /* Temporary node pointer */
  862.  
  863.   /* Functions called */
  864.     void sort_freq();
  865.     NODE *new_node();
  866.     char *malloc();
  867.  
  868. /***************************************************************************
  869.   Allocate the array of nodes from memory and initialize these with numbers
  870.   corresponding with the frequency list.  There are only 511 possible
  871.   permutations of first difference histograms.  There are 512 allocated
  872.   here to adhere to the FORTRAN version.
  873. ****************************************************************************/
  874.  
  875.    fp = freq_list;
  876.    node_list = (NODE **) malloc(sizeof(temp)*512);
  877.    if (node_list == NULL)
  878.     {
  879.       printf("\nOut of memory in huff_tree!\n");
  880.       exit(1);
  881.     }
  882.    np = node_list;
  883.  
  884.    for (num_nodes=1, cnt=512 ; cnt-- ; num_nodes++)
  885.      {
  886. /**************************************************************************
  887.     The following code has been added to standardize the VAX byte order
  888.     for the "long int" type.  This code is intended to make the routine
  889.     as machine independant as possible.
  890. ***************************************************************************/
  891.         unsigned char *cp = (unsigned char *) hist++;
  892.         unsigned long int j;
  893.         short int i;
  894.         for (i=4 ; --i >= 0 ; j = (j << 8) | *(cp+i));
  895.  
  896. /* Now make the assignment */
  897.         *fp++ = j;
  898.         temp = new_node(num_nodes);
  899.         *np++ = temp;
  900.      }
  901.  
  902.      (*--fp) = 0;         /* Ensure the last element is zeroed out.  */
  903.  
  904. /***************************************************************************
  905.   Now, sort the frequency list and eliminate all frequencies of zero.
  906. ****************************************************************************/
  907.  
  908.   num_freq = 512;
  909.   sort_freq(freq_list,node_list,num_freq);
  910.  
  911.   fp = freq_list;
  912.   np = node_list;
  913.  
  914.   for (num_freq=512 ; (*fp) == 0 && (num_freq) ; fp++, np++, num_freq--);
  915.  
  916.  
  917. /***************************************************************************
  918.   Now create the tree.  Note that if there is only one difference value,
  919.   it is returned as the root.  On each interation, a new node is created
  920.   and the least frequently occurring difference is assigned to the right
  921.   pointer and the next least frequency to the left pointer.  The node
  922.   assigned to the left pointer now becomes the combination of the two
  923.   nodes and it's frequency is the sum of the two combining nodes.
  924. ****************************************************************************/
  925.  
  926.   for (temp=(*np) ; (num_freq--) > 1 ; )
  927.     {
  928.         temp = new_node(znull);
  929.         temp->right = (*np++);
  930.         temp->left = (*np);
  931.         *np = temp;
  932.         *(fp+1) = *(fp+1) + *fp;
  933.         *fp++ = 0;
  934.         sort_freq(fp,np,num_freq);
  935.     }
  936.  
  937.   return temp;
  938.  }
  939.  
  940. NODE *new_node(value)
  941. /****************************************************************************
  942. *_TITLE new_node - allocates a NODE structure and returns a pointer to it   *
  943. *_ARGS  TYPE        NAME        I/O     DESCRIPTION                         */
  944.         short int   value;    /* I      Value to assign to DN field         */
  945.  
  946.   {
  947.     NODE *temp;         /* Pointer to the memory block */
  948.  
  949.     char *malloc();     /* Memory allocation function */
  950.  
  951. /***************************************************************************
  952.   Allocate the memory and intialize the fields.
  953. ****************************************************************************/
  954.  
  955.   temp = (NODE *) malloc(sizeof(NODE));
  956.  
  957.   if (temp != NULL)
  958.     {
  959.       temp->right = NULL;
  960.       temp->dn = value;
  961.       temp->left = NULL;
  962.     }
  963.   else
  964.     {
  965.        printf("\nOut of memory in new_node!\n");
  966.        exit(1);
  967.     }
  968.  
  969.    return temp;
  970.   }
  971.  
  972.  void sort_freq(freq_list,node_list,num_freq)
  973. /****************************************************************************
  974. *_TITLE sort_freq - sorts frequency and node lists in increasing freq. order*
  975. *_ARGS  TYPE       NAME            I/O  DESCRIPTION                         */
  976.         long int   *freq_list;   /* I   Pointer to frequency list           */
  977.         NODE       **node_list;  /* I   Pointer to array of node pointers   */
  978.         long int   num_freq;     /* I   Number of values in freq list       */
  979.  
  980.   {
  981.     /* Local Variables */
  982.     register long int *i;       /* primary pointer into freq_list */
  983.     register long int *j;       /* secondary pointer into freq_list */
  984.  
  985.     register NODE **k;          /* primary pointer to node_list */
  986.     register NODE **l;          /* secondary pointer into node_list */
  987.  
  988.     long int temp1;             /* temporary storage for freq_list */
  989.     NODE *temp2;                /* temporary storage for node_list */
  990.  
  991.     register long int cnt;      /* count of list elements */
  992.  
  993.  
  994. /************************************************************************
  995.   Save the current element - starting with the second - in temporary
  996.   storage.  Compare with all elements in first part of list moving
  997.   each up one element until the element is larger.  Insert current
  998.   element at this point in list.
  999. *************************************************************************/
  1000.  
  1001.    if (num_freq <= 0) return;      /* If no elements or invalid, return */
  1002.  
  1003.    for (i=freq_list, k=node_list, cnt=num_freq ; --cnt ; *j=temp1, *l=temp2)
  1004.      {
  1005.         temp1 = *(++i);
  1006.         temp2 = *(++k);
  1007.  
  1008.         for (j = i, l = k ;  *(j-1) > temp1 ; )
  1009.           {
  1010.             *j = *(j-1);
  1011.             *l = *(l-1);
  1012.             j--;
  1013.             l--;
  1014.             if ( j <= freq_list) break;
  1015.           }
  1016.  
  1017.      }
  1018.   return;
  1019.   }
  1020.  
  1021.  void dcmprs(ibuf,obuf,nin,nout,root)
  1022. /****************************************************************************
  1023. *_TITLE dcmprs - decompresses Huffman coded compressed image lines          *
  1024. *_ARGS  TYPE       NAME       I/O       DESCRIPTION                         */
  1025.         char       *ibuf;   /* I        Compressed data buffer              */
  1026.         char       *obuf;   /* O        Decompressed image line             */
  1027.         long int   *nin;    /* I        Number of bytes on input buffer     */
  1028.         long int   *nout;   /* I        Number of bytes in output buffer    */
  1029.         NODE       *root;   /* I        Huffman coded tree                  */
  1030.  
  1031.   {
  1032.     /* Local Variables */
  1033.     register NODE *ptr = root;        /* pointer to position in tree */
  1034.     register unsigned char test;      /* test byte for bit set */
  1035.     register unsigned char idn;       /* input compressed byte */
  1036.  
  1037.     register char odn;                /* last dn value decompressed */
  1038.  
  1039.     char *ilim = ibuf + *nin;         /* end of compressed bytes */
  1040.     char *olim = obuf + *nout;        /* end of output buffer */
  1041.  
  1042. /**************************************************************************
  1043.   Check for valid input values for nin, nout and make initial assignments.
  1044. ***************************************************************************/
  1045.  
  1046.     if (ilim > ibuf && olim > obuf)
  1047.        odn = *obuf++ = *ibuf++;
  1048.     else
  1049.        {
  1050.            printf("\nInvalid byte count in dcmprs!\n");
  1051.            exit(1);
  1052.        }
  1053.  
  1054. /**************************************************************************
  1055.   Decompress the input buffer.  Assign the first byte to the working
  1056.   variable, idn.  An arithmatic and (&) is performed using the variable
  1057.   'test' that is bit shifted to the right.  If the result is 0, then
  1058.   go to right else go to left.
  1059. ***************************************************************************/
  1060.  
  1061.     for (idn=(*ibuf) ; ibuf < ilim  ; idn =(*++ibuf))
  1062.      {
  1063.         for (test=0x80 ; test ; test >>= 1)
  1064.            {
  1065.             ptr = (test & idn) ? ptr->left : ptr->right;
  1066.  
  1067.             if (ptr->dn != -1)
  1068.               {
  1069.                 if (obuf >= olim) return;
  1070.                 odn -= ptr->dn + 256;
  1071.                 *obuf++ = odn;
  1072.                 ptr = root;
  1073.               }
  1074.           }
  1075.      }
  1076.    return;
  1077.   }
  1078.