/**********************                                                       
* standard C includes *                                                       
**********************/                                                       
#include <stdio.h>                                                            
#include <string.h>                                                           
#include <stdlib.h>                                                           
#include <ctype.h>                                                            
#include <time.h>                                                             
#include <math.h>                                                             
#ifdef unix                                                                   
#include <unistd.h>                                                           
#include </sys/sys/stat.h>                                                    
#include </sys/sys/fcntlcom.h>                                                
#endif                                                                        
                                                                              
#define SEEK_SET 0                                                            
                                                                              
/**************************                                                   
* subroutine declarations *                                                   
**************************/                                                   
void rpdslabs();                                                              
void status();                                                                
void readimg();                                                               
void writeimg();                                                              
void wpdslabs();                                                              
                                                                              
/*******************                                                          
* global variables *                                                          
*******************/                                                          
unsigned char *inbuf;                                                         
unsigned char *oubuf;                                                         
unsigned char *inarray;                                                       
unsigned char *ouarray;                                                       
unsigned char *iloc;                                                          
unsigned char *oloc;                                                          
char *ipdslab;                                                                
char *opdslab;                                                                
char inname[80];                                                              
char outname[80];                                                             
#ifdef unix                                                                   
long int infile;                                                              
#else                                                                         
FILE *infile;                                                                 
#endif                                                                        
FILE *outfile;                                                                
short int nf;                                                                 
                                                                              
struct {                                                                      
	long int rec_bytes;                                                          
	long int file_rec;                                                           
	long int lab_rec;                                                            
	long int imgptr;                                                             
	float line_poff;                                                             
	float samp_poff;                                                             
} k;                                                                          
                                                                              
main(argc,argv)                                                               
long int argc;                                                                
char **argv;                                                                  
{                                                                             
   short int inum;                                                            
   long int i,j,il,ilo,inli,inl;                                              
   long int icnt,nlines;                                                      
                                                                              
/*****************************************************************            
* if the user has not input parameters through the command line, *            
* then give an example of the command line format and exit       *            
*****************************************************************/            
   if (argc == 1) {                                                           
     printf("\nPATCH Label Correction Program. Command line format:\n\n");    
     printf("PATCH from to\n\n");                                             
     printf("from     - Name of the input image file.\n\n");                  
     printf("to       - Name of the output image file. The output image ");   
     printf("file name is\n           optional. If you do not specify an ");  
     printf("output image file name, then\n           all changes will ");    
     printf("be made directly to the input file.\n\n\n\n");                   
     exit(0);                                                                 
   }                                                                          
   nf = argc - 1;                                                             
   printf("\n*** PATCH: Label Correction ***\n");                             
                                                                              
/**************************************                                       
* acquire input and output file names *                                       
**************************************/                                       
   strcpy(inname,argv[1]);                                                    
   if (nf == 2) strcpy(outname,argv[2]);                                      
   if (strcmp(inname,outname) == 0) nf = 1;                                   
                                                                              
/***************************************************************              
* open the input image file and read the pds label information *              
***************************************************************/              
#ifdef unix                                                                   
   if ((infile = open(inname,O_RDONLY)) <= 0) {                               
#else                                                                         
   if ((infile = fopen(inname,"rb")) == 0) {                                  
#endif                                                                        
     printf("*** ERROR *** Can't open the input image file: %s\n",inname);    
     exit(0);                                                                 
   }                                                                          
   rpdslabs();                                                                
                                                                              
/*******************************************************                      
* correct the line and sample projection offset values *                      
*******************************************************/                      
   k.line_poff = -k.line_poff;                                                
   k.samp_poff = -k.samp_poff;                                                
                                                                              
/***********************                                                      
* main processing loop *                                                      
***********************/                                                      
   printf(" \n");                                                             
                                                                              
   if (nf == 2) {                                                             
     i = 0;                                                                   
     nlines = k.file_rec - k.lab_rec;                                         
     status(i,nlines);                                                        
     inli = 60000/k.rec_bytes;                                                
     if ((inbuf = (unsigned char *) malloc(60416)) == NULL) {                 
       printf("*** ERROR *** Unable to allocate memory for processing\n");    
       exit(0);                                                               
     }                                                                        
     i = inli*k.rec_bytes;                                                    
     if ((inarray = (unsigned char *) malloc(i)) == NULL) {                   
       printf("*** ERROR *** Unable to allocate memory for processing\n");    
       exit(0);                                                               
     }                                                                        
#ifdef unix                                                                   
     close(infile);                                                           
     if ((infile = open(inname,O_RDONLY)) <= 0) {                             
#else                                                                         
     fclose(infile);                                                          
     if ((infile = fopen(inname,"rb")) == NULL) {                             
#endif                                                                        
       printf("*** ERROR *** Can't open the input image file: %s\n",inname);  
       exit(0);                                                               
     }                                                                        
#ifdef unix                                                                   
#else                                                                         
     setvbuf(infile,inbuf,_IOFBF,60416);                                      
#endif                                                                        
     if ((oubuf = (unsigned char *) malloc(60416)) == NULL) {                 
       printf("*** ERROR *** Unable to allocate memory for processing\n");    
       exit(0);                                                               
     }                                                                        
     i = inli*k.rec_bytes;                                                    
     if ((ouarray = (unsigned char *) malloc(i)) == NULL) {                   
       printf("*** ERROR *** Unable to allocate memory for processing\n");    
       exit(0);                                                               
     }                                                                        
                                                                              
/*******************************************************                      
* open the output image file if the user specified one *                      
*******************************************************/                      
     remove(outname);                                                         
     if ((outfile = fopen(outname,"wb")) == NULL) {                           
       printf("*** ERROR *** Can't open the output image file: %s\n",         
              outname);                                                       
       exit(0);                                                               
     }                                                                        
     setvbuf(outfile,oubuf,_IOFBF,60416);                                     
                                                                              
     i = k.lab_rec*k.rec_bytes;                                               
#ifdef unix                                                                   
     if ((j = lseek(infile,i,SEEK_SET)) != i) {                               
#else                                                                         
     if ((j = fseek(infile,i,SEEK_SET)) != 0) {                               
#endif                                                                        
       printf("*** ERROR *** Unable to read image data from ");               
       printf("input image file\n");                                          
       exit(0);                                                               
     }                                                                        
                                                                              
     for (j=0; j<k.rec_bytes; j++)                                            
       ouarray[j] = 0;                                                        
     for (icnt=0; icnt<k.lab_rec; icnt++) {                                   
       if (fwrite(ouarray,k.rec_bytes,1,outfile) != 1) {                      
         printf("*** ERROR *** Unable to write to the output image file\n");  
         exit(0);                                                             
       }                                                                      
     }                                                                        
     ilo = 1;                                                                 
     fflush(outfile);                                                         
                                                                              
     inl = inli - 1;                                                          
     inum = 0;                                                                
     icnt = inli*k.rec_bytes;                                                 
     for (il=1; il<=nlines; il++) {                                           
                                                                              
/*****************************************************                        
* read a line from the input image file into inarray *                        
*****************************************************/                        
       if (inum == 0) {                                                       
         if (il > 1) writeimg(&inl);                                          
         i = nlines - il + 1;                                                 
         if (inl > i) inl = i;                                                
         readimg(&inl);                                                       
         inum = inl;                                                          
         iloc = inarray;                                                      
         oloc = ouarray;                                                      
         for (j=0; j<icnt; j++)                                               
           ouarray[j] = 0;                                                    
       }                                                                      
       inum--;                                                                
                                                                              
       for (i=0; i<k.rec_bytes; i++)                                          
         oloc[i] = iloc[i];                                                   
                                                                              
       ilo++;                                                                 
       iloc+=k.rec_bytes;                                                     
       oloc+=k.rec_bytes;                                                     
       status(il,nlines);                                                     
     }                                                                        
                                                                              
     writeimg(&inl);                                                          
                                                                              
/****************************************************                         
* free the memory taken up by the image data arrays *                         
****************************************************/                         
     free(inarray);                                                           
     free(ouarray);                                                           
                                                                              
/*********************************************                                
* update the labels in the output image file *                                
*********************************************/                                
     if (fseek(outfile,0,SEEK_SET) != 0) {                                    
       printf("*** ERROR *** Problem updating the output file labels\n");     
       exit(0);                                                               
     }                                                                        
                                                                              
     i = 0;                                                                   
     wpdslabs(i);                                                             
                                                                              
     fflush(outfile);                                                         
     fclose(outfile);                                                         
     free(oubuf);                                                             
   }                                                                          
   else {                                                                     
     inli = ((k.rec_bytes*k.lab_rec + 511)/512)*512;                          
     if ((inbuf = (unsigned char *) malloc(inli)) == NULL) {                  
       printf("*** ERROR *** Unable to allocate memory for processing\n");    
       exit(0);                                                               
     }                                                                        
     if ((inarray = (unsigned char *) malloc(inli)) == NULL) {                
       printf("*** ERROR *** Unable to allocate memory for processing\n");    
       exit(0);                                                               
     }                                                                        
#ifdef unix                                                                   
     close(infile);                                                           
     if ((i = chmod(inname,S_IREAD | S_IWRITE)) != 0) {                       
       printf("*** ERROR *** Unable to open input image file for ");          
       printf("read/write access\n");                                         
       exit(0);                                                               
     }                                                                        
     if ((infile = open(inname,O_RDWR)) <= 0) {                               
#else                                                                         
     fclose(infile);                                                          
     if ((infile = fopen(inname,"rb+")) == NULL) {                            
#endif                                                                        
       printf("*** ERROR *** Can't open the input image file: %s\n",inname);  
       exit(0);                                                               
     }                                                                        
#ifdef unix                                                                   
#else                                                                         
     setvbuf(infile,inbuf,_IOFBF,inli);                                       
#endif                                                                        
     i = 1;                                                                   
     wpdslabs(i);                                                             
#ifdef unix                                                                   
#else                                                                         
     fflush(infile);                                                          
#endif                                                                        
   }                                                                          
                                                                              
   free(ipdslab);                                                             
   free(opdslab);                                                             
#ifdef unix                                                                   
   close(infile);                                                             
#else                                                                         
   fclose(infile);                                                            
#endif                                                                        
   free(inbuf);                                                               
                                                                              
   printf("\n*** END OF PATCH ***\n");                                        
}                                                                             
                                                                              
/******************************************************                       
* rpdslabs - read in the pds labels of the image file *                       
******************************************************/                       
void rpdslabs()                                                               
{                                                                             
   char *bufr;                                                                
   char *ptr;                                                                 
   long int i,j,ij,icnt,nbytes;                                               
                                                                              
   if ((bufr = malloc(512)) == NULL) {                                        
     printf("*** ERROR *** Unable to allocate memory for image labels\n");    
     exit(0);                                                                 
   }                                                                          
#ifdef unix                                                                   
   if ((i = read(infile,bufr,512)) != 512) {                                  
#else                                                                         
   if ((i = fread(bufr,1,512,infile)) != 512) {                               
#endif                                                                        
     printf("*** ERROR *** Problem reading the input image file labels\n");   
     exit(0);                                                                 
   }                                                                          
   if (strstr(bufr,"= FIXED_LENGTH") == NULL) {                               
     printf("*** ERROR *** The input file has not been decompressed\n");      
     exit(0);                                                                 
   }                                                                          
   if ((ptr = strstr(bufr,"RECORD_BYTES")) == NULL) {                         
     printf("*** ERROR *** RECORD_BYTES keyword is missing\n");               
     exit(0);                                                                 
   }                                                                          
   else                                                                       
     k.rec_bytes = atoi((ptr=strchr(ptr,'=')+2));                             
   if ((ptr = strstr(bufr,"FILE_RECORDS")) == NULL) {                         
     printf("*** ERROR *** FILE_RECORDS keyword is missing\n");               
     exit(0);                                                                 
   }                                                                          
   else                                                                       
     k.file_rec = atoi((ptr=strchr(ptr,'=')+2));                              
   if ((ptr = strstr(bufr,"LABEL_RECORDS")) == NULL) {                        
     printf("*** ERROR *** LABEL_RECORDS keyword is missing\n");              
     exit(0);                                                                 
   }                                                                          
   else                                                                       
     k.lab_rec = atoi((ptr=strchr(ptr,'=')+2));                               
   free(bufr);                                                                
                                                                              
   if (nf == 2) {                                                             
     i = k.lab_rec*k.rec_bytes;                                               
     icnt = k.lab_rec;                                                        
     nbytes = k.rec_bytes;                                                    
   }                                                                          
   else {                                                                     
     i = ((k.lab_rec*k.rec_bytes + 511)/512)*512;                             
     icnt = i/512;                                                            
     nbytes = 512;                                                            
   }                                                                          
   if ((ipdslab = malloc(i)) == NULL) {                                       
     printf("*** ERROR *** Unable to allocate memory for labels\n");          
     exit(0);                                                                 
   }                                                                          
#ifdef unix                                                                   
   if (lseek(infile,0,SEEK_SET) != 0) {                                       
#else                                                                         
   if (fseek(infile,0,SEEK_SET) != 0) {                                       
#endif                                                                        
     printf("*** ERROR *** Problem reading the input file labels\n");         
     exit(0);                                                                 
   }                                                                          
   j = 0;                                                                     
   for (ij=0; ij<icnt; ij++) {                                                
#ifdef unix                                                                   
     if ((read(infile,&(ipdslab[j]),nbytes)) !=                               
         nbytes) {                                                            
#else                                                                         
     if ((fread(&(ipdslab[j]),1,nbytes,infile)) !=                            
         nbytes) {                                                            
#endif                                                                        
       printf("*** ERROR *** Problem reading the input file labels\n");       
       exit(0);                                                               
     }                                                                        
     j+=nbytes;                                                               
   }                                                                          
                                                                              
   if ((ptr = strstr(ipdslab,"^IMAGE  ")) != NULL)                            
     k.imgptr = atoi((ptr=strchr(ptr,'=')+2));                                
   else {                                                                     
     printf("*** ERROR *** ^IMAGE keyword is missing\n");                     
     exit(0);                                                                 
   }                                                                          
   if (k.imgptr <= 0) {                                                       
     printf("*** ERROR *** Invalid image pointer value in labels\n");         
     exit(0);                                                                 
   }                                                                          
   k.line_poff = 0.;                                                          
   if ((ptr = strstr(ipdslab,"LINE_PROJECTION_OFFSET")) != NULL)              
     sscanf((ptr=strchr(ptr,'=')+2),"%f.3",&k.line_poff);                     
   k.samp_poff = 0.;                                                          
   if ((ptr = strstr(ipdslab,"SAMPLE_PROJECTION_OFFSET")) != NULL)            
     sscanf((ptr=strchr(ptr,'=')+2),"%f.3",&k.samp_poff);                     
}                                                                             
                                                                              
/**************************************************                           
* status - report status of a function's progress *                           
**************************************************/                           
void status(curval,endval)                                                    
long int curval,endval;                                                       
{                                                                             
   static long int oldsts=0;                                                  
   static long int newsts;                                                    
   static float pct;                                                          
                                                                              
   pct = ((float) curval/(float) endval)*100.;                                
   newsts = (int) pct;                                                        
   if (newsts >= oldsts) {                                                    
     printf("%d %% done\r",newsts);                                           
     fflush(stdout);                                                          
     oldsts = oldsts + 5;                                                     
   }                                                                          
}                                                                             
                                                                              
/****************************************************************             
* readimg - reads a line from the input image file into inarray *             
****************************************************************/             
void readimg(inli)                                                            
long int *inli;                                                               
{                                                                             
   long int i,j;                                                              
                                                                              
   i = (*inli)*k.rec_bytes;                                                   
#ifdef unix                                                                   
   if ((read(infile,inarray,i)) != i) {                                       
#else                                                                         
   if ((fread(inarray,i,1,infile)) != 1) {                                    
#endif                                                                        
     printf("*** ERROR *** Problem reading the image data from ");            
     printf("the input image file\n");                                        
     exit(0);                                                                 
   }                                                                          
#ifdef unix                                                                   
#else                                                                         
   fflush(infile);                                                            
#endif                                                                        
}                                                                             
                                                                              
/*********************************************************************        
* writeimg - writes the contents of ouarray to the output image file *        
*********************************************************************/        
void writeimg(inli)                                                           
long int *inli;                                                               
{                                                                             
   long int i;                                                                
                                                                              
   i = (*inli)*k.rec_bytes;                                                   
   if (fwrite(ouarray,i,1,outfile) != 1) {                                    
     printf("*** ERROR *** Unable to write to the output image file\n");      
     exit(0);                                                                 
   }                                                                          
   fflush(outfile);                                                           
}                                                                             
                                                                              
/***********************************************************                  
* wpdslabs - write the pds labels to the output image file *                  
***********************************************************/                  
void wpdslabs(ifile)                                                          
long int ifile;                                                               
{                                                                             
   char crr[2],lff[2];                                                        
   char *ptr="";                                                              
   char *ptr1="";                                                             
   char *ptr2="";                                                             
   long int itot,i,ilen;                                                      
   long int idec;                                                             
   unsigned char cr=13,lf=10,blank=32;                                        
                                                                              
   void fltupd();                                                             
                                                                              
   strcpy(crr,"");                                                            
   strcpy(lff,"");                                                            
   strncat(crr,&cr,1);                                                        
   strncat(lff,&lf,1);                                                        
   if (nf == 2)                                                               
     i = k.lab_rec*k.rec_bytes;                                               
   else                                                                       
     i = ((k.lab_rec*k.rec_bytes + 511)/512)*512;                             
   if ((opdslab = malloc(i)) == NULL) {                                       
     printf("*** ERROR *** Unable to allocate memory for labels\n");          
     exit(0);                                                                 
   }                                                                          
   strcpy(&(opdslab[0]),"");                                                  
   itot = 0;                                                                  
   idec = 4;                                                                  
   fltupd("LINE_PROJECTION_OFFSET",&ptr,&ptr1,&ptr2,&itot,&idec,crr,lff,      
          &k.line_poff);                                                      
   fltupd("SAMPLE_PROJECTION_OFFSET",&ptr,&ptr1,&ptr2,&itot,&idec,crr,lff,    
          &k.samp_poff);                                                      
                                                                              
   strncpy(&(opdslab[itot]),ptr2,(ilen=strlen(ptr2)));                        
   itot = itot + ilen;                                                        
   strncpy(&(opdslab[itot]),"",1);                                            
   ilen = k.lab_rec*k.rec_bytes;                                              
   if (itot < ilen) {                                                         
     for (i=itot; i<ilen; i++)                                                
       strncat(&(opdslab[i]),&blank,1);                                       
   }                                                                          
                                                                              
   if (ifile == 0) {                                                          
     if (fwrite(opdslab,ilen,1,outfile) != 1) {                               
       printf("*** ERROR *** Unable to write labels to the image ");          
       printf("file\n");                                                      
       exit(0);                                                               
     }                                                                        
   }                                                                          
   else {                                                                     
     ilen = ((ilen+511)/512)*512;                                             
#ifdef unix                                                                   
     if (write(infile,opdslab,ilen) != ilen) {                                
#else                                                                         
     if (fwrite(opdslab,ilen,1,infile) != 1) {                                
#endif                                                                        
       printf("*** ERROR *** Unable to write labels to the image ");          
       printf("file\n");                                                      
       exit(0);                                                               
     }                                                                        
   }                                                                          
}                                                                             
                                                                              
/******************************************************                       
* flttoasc - convert a float to its string equivalent *                       
******************************************************/                       
void flttoasc(rnum,idec,bufr)                                                 
float *rnum;                                                                  
long int *idec;                                                               
char *bufr;                                                                   
{                                                                             
   char *numbers="0123456789";                                                
   long int i,j,m,tmpnum,iset,ival;                                           
   float rval;                                                                
                                                                              
   rval = *rnum;                                                              
   ival = rval;                                                               
   rval = rval - ival;                                                        
   for (i=0; i<*idec; i++)                                                    
     rval = rval*10;                                                          
   ival = rval;                                                               
   rval = *rnum;                                                              
   iset = 0;                                                                  
   strcpy(bufr,"");                                                           
   j = 1000000000;                                                            
   if (rval < 0.) {                                                           
     strncat(bufr,"-",1);                                                     
     rval = -rval;                                                            
     ival = -ival;                                                            
   }                                                                          
   for (i=0; i<10; i++) {                                                     
     tmpnum = rval/j;                                                         
     if (tmpnum > 0 || iset == 1) {                                           
       iset = 1;                                                              
       rval = rval - tmpnum*j;                                                
       strncat(bufr,&numbers[tmpnum],1);                                      
     }                                                                        
     j = j/10;                                                                
   }                                                                          
   if (iset == 0) strncat(bufr,"0",1);                                        
   strncat(bufr,".",1);                                                       
   j = 1;                                                                     
   for (m=1; m<*idec; m++)                                                    
     j = j*10;                                                                
   for (i=1; i<=*idec; i++) {                                                 
     tmpnum = ival/j;                                                         
     ival = ival - tmpnum*j;                                                  
     strncat(bufr,&numbers[tmpnum],1);                                        
     j = j/10;                                                                
   }                                                                          
}                                                                             
                                                                              
/*************************************************                            
* fltupd - update a real value in the pds labels *                            
*************************************************/                            
void fltupd(search,ptr,ptr1,ptr2,itot,idec,crr,lff,rval)                      
char *search;                                                                 
char **ptr,**ptr1,**ptr2;                                                     
long int *itot,*idec;                                                         
char *crr,*lff;                                                               
float *rval;                                                                  
{                                                                             
   char bufr[15];                                                             
   long int ilen;                                                             
                                                                              
   void flttoasc();                                                           
                                                                              
   if (*itot == 0)                                                            
     *ptr = ipdslab;                                                          
   else                                                                       
     *ptr = *ptr2;                                                            
                                                                              
   *ptr1 = strstr(*ptr,search);                                               
   *ptr2 = strchr((*ptr1=strchr(*ptr1,'=')+2),13) + 2;                        
   strncpy(&(opdslab[*itot]),*ptr,(ilen=(*ptr1)-(*ptr)));                     
   flttoasc(rval,idec,bufr);                                                  
   *itot = *itot + ilen;                                                      
   strncpy(&(opdslab[*itot]),bufr,(ilen=strlen(bufr)));                       
   *itot = *itot + ilen;                                                      
   strncpy(&(opdslab[*itot]),crr,1);                                          
   *itot = *itot + 1;                                                         
   strncpy(&(opdslab[*itot]),lff,1);                                          
   *itot = *itot + 1;                                                         
}