/* *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* */ /* ** Copyright UCAR (c) 1990 - 2016 */ /* ** University Corporation for Atmospheric Research (UCAR) */ /* ** National Center for Atmospheric Research (NCAR) */ /* ** Boulder, Colorado, USA */ /* ** BSD licence applies - redistribution and use in source and binary */ /* ** forms, with or without modification, are permitted provided that */ /* ** the following conditions are met: */ /* ** 1) If the software is modified to produce derivative works, */ /* ** such modified software should be clearly marked, so as not */ /* ** to confuse it with the version available from UCAR. */ /* ** 2) Redistributions of source code must retain the above copyright */ /* ** notice, this list of conditions and the following disclaimer. */ /* ** 3) Redistributions in binary form must reproduce the above copyright */ /* ** notice, this list of conditions and the following disclaimer in the */ /* ** documentation and/or other materials provided with the distribution. */ /* ** 4) Neither the name of UCAR nor the names of its contributors, */ /* ** if any, may be used to endorse or promote products derived from */ /* ** this software without specific prior written permission. */ /* ** DISCLAIMER: THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS */ /* ** OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */ /* ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* */ /****************************************************************** File: gint_user.c Routines for the users of gint-save_volume *****************************************************************/ #define GINT_USER #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <sys/types.h> #include <sys/file.h> #include <fcntl.h> #include <toolsa/os_config.h> #include <rapformats/gint_user.h> /****************************************************************** * GINT_FREE_HEADER: Free up any allocated memory in the Gint * Tvolume_header */ int GINT_free_header(Tvolume_header *hd) { if(hd->vh) { free(hd->vh); hd->vh = NULL; } if(hd->fi) { free(hd->fi); hd->fi = NULL; } if(hd->ai) { free(hd->ai); hd->ai = NULL; } if(hd->li) { free(hd->li); hd->li = NULL; } return 0; } /****************************************************************** * GET_HEADER: Gets the file's header information. This version * Allocates space for header data, if pointers are set to null. * If pointers are non-null - They are first freed, then reallocated * Users should call GINT_free_header to deallocate space. */ int GINT_get_header(Tvolume_header *hd,FILE *file) { if(hd->vh == NULL) { if((hd->vh = (Volume_header *) calloc(1,sizeof(Volume_header))) == NULL ) { printf("Cannot allocate memory - -gint_user.c.\n"); return(1); } } /* read v header */ if(fseek(file,0,SEEK_SET)<0) { printf("Error fseek (0) -gint_user.c.\n"); return (1); } if(fread(hd->vh,sizeof(Volume_header),1,file)!= 1) { printf("Failed in reading the header (0) - gint_user.c.\n"); return (1); } #ifdef DBG /* check data id */ if(hd->vh->data_id[0]==' ' || hd->vh->data_id[0]=='\0'){ printf("Data_id error in header - gint_user.c ID = %s\n", hd->vh->data_id); return (1); } #endif /* ALLOCATE SPACE FOR FIELD INFO and READ */ if(hd->fi !=NULL ) free(hd->fi); if((hd->fi=(Field_infor *)calloc(hd->vh->n_fields,sizeof(Field_infor))) == NULL){ printf("Failed in allocating space for header - gint_user.c.\n"); return (1); } if(fread(hd->fi,sizeof(Field_infor),hd->vh->n_fields,file)!=hd->vh->n_fields) { printf("Failed in reading remaining hd - gint_user.c.\n"); return (1); } /* ALLOCATE SPACE FOR ALTITUDE INFO and READ */ if(hd->ai !=NULL ) free(hd->ai); if((hd->ai=(Altitude_infor *)calloc(hd->vh->nz,sizeof(Altitude_infor))) == NULL){ printf("Failed in allocating space for header - gint_user.c.\n"); return (1); } if(fread(hd->ai,sizeof(Altitude_infor),hd->vh->nz,file)!=hd->vh->nz) { printf("Failed in reading remaining hd - gint_user.c.\n"); return (1); } /* ALLOCATE SPACE FOR DATA PLANE FILE LOCATION INFO and READ */ if(hd->li !=NULL ) free(hd->li); if((hd->li=(Location_infor *)calloc(hd->vh->n_fields*hd->vh->nz,sizeof(Location_infor))) == NULL){ printf("Failed in allocating space for header - gint_user.c.\n"); return (1); } if(fread(hd->li,sizeof(Location_infor),hd->vh->n_fields*hd->vh->nz,file)!=hd->vh->n_fields*hd->vh->nz) { printf("Failed in reading remaining hd - gint_user.c.\n"); return (1); } if(hd->vh->encode==0){ /* we add default loc and size */ int c_size,i,cnt,t,sz; c_size=sizeof(Volume_header)+hd->vh->n_fields*sizeof(Field_infor)+ hd->vh->nz*sizeof(Altitude_infor)+hd->vh->nz*hd->vh->n_fields*sizeof(Location_infor); t=hd->vh->nz*hd->vh->n_fields; cnt=c_size; sz=hd->vh->nx*hd->vh->ny; for(i=0;i<t;i++){ hd->li[i].off=cnt; hd->li[i].len=sz; cnt += sz; } } return(0); } /******************************************************************** * GET_PLANE : get a cappi plane. Return a pointor to the data of * decoded cappi, or NULL in case of failure */ unsigned char *GINT_get_plane(int field, int cappi_ind, FILE *file, Tvolume_header *hd) { unsigned char *buf,*ipt; int offset,len,ind,nxy; /* check */ if(field<0 || field>=hd->vh->n_fields || cappi_ind<0 || cappi_ind>=hd->vh->nz || file == NULL) return (NULL); /* allocate the space */ nxy = hd->vh->nx * hd->vh->ny; if((buf=(unsigned char *)calloc(1,nxy))==NULL){ printf("Failed in allocating cappi space.\n"); return (NULL); } offset=hd->li[field+hd->vh->n_fields*cappi_ind].off; len=hd->li[field+hd->vh->n_fields*cappi_ind].len; /* read a cappi */ if(fseek(file,offset,SEEK_SET)<0){ printf("Failed in lseek (%d) - gint_user.c.\n",offset); return (NULL); } offset=hd->vh->nx*hd->vh->ny-len; ipt=buf+offset; if(fread(ipt,len,1,file)!=1){ printf("Failed in reading field: %d cappi: %d, len: %d.\n",field, cappi_ind,len); return (NULL); } /* decode */ switch(hd->vh->encode) { case NOT_ENCODED: break; case RL7_ENCODED: { ind = GINT_run_length_decode(len,ipt,buf); if (ind > nxy) { free(buf); return NULL; } break; } case RL8_ENCODED: { ind = GINT_run_length_decode_byte(len,ipt,buf); if (ind > nxy) { free(buf); return NULL; } break; } } return (buf); } /******************************************************************* * GINT_RUN_LENGTH_ENCODE_BYTE: * run length encode of 8 bit string. * 255 is used for control code and all 255 data are changed * to be 254 * * Calling routine must allocate enough space for encoded * data. * * Returns the length of the encoded data */ int GINT_run_length_encode_byte(int len, unsigned char *stri,unsigned char *stro) { unsigned char *ipt,*opt,*ept,tmp,*tpt; int i,nrun; ipt=stri; opt=stro; ept=ipt+len; while(ipt<ept){ tmp=*ipt; /* find number of runs */ tpt=ipt+1; while(tpt<ept && *tpt==tmp) tpt++; nrun=tpt-ipt; if(nrun==1){ if(tmp==255) *opt++=254; else *opt++=tmp; ipt++; } else if(nrun<4){ for(i=0;i<nrun;i++){ if(*ipt==255) *opt++=254; else *opt++=*ipt; ipt++; } } else{ if(nrun>254) nrun=254; *opt++=255; *opt++=nrun; if(tmp==255) tmp=254; *opt++=tmp; ipt+=nrun; } } return ((int)(opt-stro)); } /******************************************************************* * GINT_RUN_LENGTH_DECODE_BYTE: * run length decode of 8 bit string. * * The Calling routine must allocate enough space for the decoded data * Returns the length of the decoded data array */ int GINT_run_length_decode_byte( int len, unsigned char *stri, unsigned char *stro) { unsigned char *ipt,*opt,*ept,tmp; int i,nrun; ipt=stri; opt=stro; ept=ipt+len; while(ipt<ept){ if(*ipt!=255){ *opt++=*ipt++; continue; } ipt++; nrun=*ipt++; tmp=*ipt++; for(i=0;i<nrun;i++) *opt++=tmp; } return ((int)(opt-stro)); } /******************************************************************* * RUN_LENGTH_ENCODE: * Run length encode of str of less then 8 bits */ int GINT_run_length_encode(int len, unsigned char *stri, unsigned char *stro,unsigned char mask) { int cnt,i,ind,max; unsigned char test,tmp; max=127; mask=mask&0xfe; cnt=0; ind=1; test=stri[0]&mask; stro[0]=test; for(i=1;i<len;i++){ tmp=stri[i]&mask; if(test==tmp && cnt<max){ cnt++; continue; } if(cnt>0) stro[ind++]=(cnt<<1)+1; stro[ind++]=tmp; test=tmp; cnt=0; } if(cnt>0) stro[ind++]=(cnt<<1)+1; return (ind); } /******************************************************************* * GINT_RUN_LENGTH_DECODE: run length decode of str of less then 8 bits * * Returns the length of the decoded array */ int GINT_run_length_decode(int len, unsigned char *stri,unsigned char *stro) { int cnt,i,ind,j; unsigned char test = 0; ind=0; for(i=0;i<len;i++){ if((stri[i]&1)==0){ stro[ind++]=stri[i]; test=stri[i]; } else{ cnt=(stri[i]>>1); for(j=0;j<cnt;j++) stro[ind++]=test; } } return (ind); } /****************************************************************** * GINT_PUT_HEADER: writes the image header */ int GINT_put_header(Tvolume_header *hd, FILE *file) { static Volume_header *vhd; int size; /* write volume header */ if(fseek(file,0,SEEK_SET)<0) { printf("Error fseek (0) -gint_user.c.\n"); return (1); } vhd=hd->vh; if(fwrite(vhd,sizeof(Volume_header),1,file)!=1){ printf("Failed in writing the header (0) - gint_user.c.\n"); return (1); } size=vhd->n_fields*sizeof(Field_infor); if(fwrite(hd->fi,size,1,file) != 1 ) { printf("Failed in writing field info header \n"); return (1); } size = vhd->nz*sizeof(Altitude_infor); if(fwrite(hd->ai,size,1,file) != 1 ) { printf("Failed in writing alt info header \n"); return (1); } size = vhd->n_fields*vhd->nz*sizeof(Location_infor); if(fwrite(hd->li,size,1,file) != 1 ) { printf("Failed in writing location info header \n"); return (1); } return(0); } /******************************************************************** * GINT_PUT_PLANE : write a plane of data. Return a non-zero flag in case * of failure: Assumes everyting in header is set correctly */ int GINT_put_plane( unsigned char *buf, int field, int cappi_ind, FILE *file, Tvolume_header *hd) { unsigned char *ipt; int offset,len; /* check */ if(field<0 || field>=hd->vh->n_fields || cappi_ind<0 || cappi_ind>=hd->vh->nz) return (1); /* calc position of data in file */ offset=hd->li[field+hd->vh->n_fields*cappi_ind].off; len=hd->li[field+hd->vh->n_fields*cappi_ind].len; /* write a cappi */ if(fseek(file,offset,SEEK_SET)<0){ printf("Failed in fseek (%d) - gint_user.c.\n",offset); return (-1); } ipt=buf; if(fwrite(ipt,len,1,file)!=1){ printf("Failed in writing the data\n"); return (-2); } return (0); } /************************************************************** * GINT_PRINT_HEADER: Print out GINT header in a nice way * Rachel Ames 1/95 * F. Hage 2/95 */ void GINT_print_header(Tvolume_header *hd, FILE *outfile) { int ifield,iz; char field_name[16]; char unit_name[16]; fprintf(outfile,"\nPrint_Header"); fprintf(outfile,"\n------------\n"); fprintf(outfile,"\nName of volume %s",hd->vh->file_name); fprintf(outfile,"\nProjection Type (CART=-1, LATLON=0) %ld",hd->vh->proj_type); fprintf(outfile,"\nNumber dimensions: nx = %ld, ny = %ld, nz = %ld",hd->vh->nx,hd->vh->ny,hd->vh->nz); fprintf(outfile,"\nGrid Spacing: (dx,dy) %ld meters", hd->vh->xss); fprintf(outfile,"\nData Encoding: %d", hd->vh->encode); fprintf(outfile,"\nNumber of fields = %ld",hd->vh->n_fields); fprintf(outfile,"\nLast time of previous volume: %s",ctime(&hd->vh->l_time)); fprintf(outfile,"Last time of current volume: %s",ctime(&hd->vh->time)); fprintf(outfile,"Origin of the grid (%ld m, %ld m) ",hd->vh->xstt,hd->vh->ystt); fprintf(outfile,"\nLongitude and Latitude of radar (%f, %f) ", hd->vh->origin_lon/1000000.,hd->vh->origin_lat/1000000.); fprintf(outfile,"\n Field units scale offset bad data value"); for (ifield = 0; ifield < hd->vh->n_fields; ifield ++) { bzero(field_name,16); bzero(unit_name,16); strncpy(field_name,hd->fi[ifield].field_names,8); strncpy(unit_name,hd->fi[ifield].unit_names,8); fprintf(outfile,"\n%8s %8s %5.3f %5.3f %xx", field_name,unit_name,hd->fi[ifield].scale/65536.,hd->fi[ifield].offset/65536., (int)hd->fi->bad_data_value); } fprintf(outfile,"\n\nAltitude Information:"); fprintf(outfile,"\nLevel #\t Height (M)"); for (iz = 0; iz < hd->vh->nz; iz ++) { fprintf(outfile,"\n%4d \t %8ld ",iz,hd->ai[iz].z); } fprintf(outfile,"\n\nPlane Location Information:"); fprintf(outfile,"\nPlane #\t len \t Offset (M)"); for (iz = 0; iz < hd->vh->nz * hd->vh->n_fields; iz ++) { fprintf(outfile,"\n%4d \t %8ld \t %8ld ",iz,hd->li[iz].len,hd->li[iz].off); } fprintf(outfile,"\n"); }