Hi Jess, re: > I can incorporate your mods, that is not a problems. Very good. re: > I don't think we'd > function very well if we couldn't since we have a lot of home grown > McIDAS commands here. :-) re: > Whenever you have a chance to send them, that'd > be great. I have attached the following files to this email: giniutil.h giniutil.c giniadir.cp giniaget.cp servutil.c Here is what I would do to incorporate the modified code: <as 'mcidas'> cd ~/bin mkdir backup mv giniadir giniaget backup cd ~/mcidas<revision>/src mkdir backup mv giniutil.h giniutil.h giniadir.cp giniaget.cp servutil.c backup -- copy the modified source files from this email to the ~/mcidas<revision>/src directory make libsdi.a giniadir giniaget && ln giniadir giniaget ~/bin re: > Thanks and have a great weekend! No worries and you too! Cheers, Tom -- **************************************************************************** Unidata User Support UCAR Unidata Program (303) 497-8642 P.O. Box 3000 address@hidden Boulder, CO 80307 ---------------------------------------------------------------------------- Unidata HomePage http://www.unidata.ucar.edu **************************************************************************** Ticket Details =================== Ticket ID: KUC-159541 Department: Support McIDAS Priority: Normal Status: Closed
/* * Copyright(c) 2004, Space Science and Engineering Center, UW-Madison * Refer to "McIDAS Software Acquisition and Distribution Policies" * in the file mcidas/data/license.txt */ /**** $Id: giniutil.h,v 1.2 2004/05/17 22:12:04 beckys Rel $ ****/ /* giniutil.h ** ** This is the main include file for the NOAAPORT GINI ADDE servers ** */ /* ** Include files */ #include <stdio.h> #include <stdlib.h> #include <strings.h> #include <unistd.h> #include "m0arg.h" /* McIDAS arg fetcher include file */ #include "mcidas.h" /* McIDAS include file */ #include "servutil.h" /* Unidata ADDE server main include file */ /* ** Build handling ** ** UNIDATA == 0 -> SSEC McIDAS build ** UNIDATA == 1 -> Unidata McIDAS build */ #ifndef UNIDATA #define UNIDATA 0 #endif /* ** Error handling */ #define ERR_STAT_MALLOC -1 /* error mallocing memory */ #define ERR_STAT_DIR -2 /* error reading directory */ #define ERR_STAT_NONAV -31 /* error error initializing navigation */ #define ERR_STAT_NOAUX -39 /* error initializing aux block */ #define ERR_STAT_NOCAL -40 /* error initializing calibration */ #define ERR_STAT_BADLINE -41 /* error reading image line */ #define ERR_STAT_BADZBLOK -42 /* error reading Zlib compressed image blk */ #define ERR_STAT_BLANK_IMG -47 /* image portion requested doesnt exist */ #define ERR_STAT_SEEK -49 /* error seeking to data portion of file */ #define ERR_STAT_SELECT -50 /* ?? */ #define ERR_STAT_NOIMG -51 /* no images meet selection criteria */ /* ** Default values */ #define DEF_NUM_ELEMS 640 /* default num of elements to send */ #define DEF_NUM_LINES 480 /* default num of lines to send */ #define READ_BUFFER_SIZE 1 /* # of image lines to buffer on read */ /* ** Nav parameters */ #define EARTH_RAD_METERS 6371200 /* Spherical earth radius [m] */ #define EARTH_ECCENTRICITY 0.0 /* earth eccentricity * 1e6 */ #define RAD_TO_DEG 57.295779 /* conversion from rads to degs */ #define DEG_TO_RAD 0.017453292 /* conversion from degs to rads */ /* ** GINI file values */ #define GINI_PIB_LEN 21 /* GINI Product Identification Block */ #define GINI_PDB_LEN 512 /* GINI Product Description Block */ #define GINI_HED_LEN 533 /* GINI Product Header */ #define GINI_ZBUF_LEN 5120 /* GINI Zlib read buffer */ /* ** GINI server utility interface prototypes */ int CalibrateGiniImgData( int, int *, unsigned char *, int , char *, int ); int GetGiniDirs( FILELIST *, int *, int *, int *, int * ); int GetGiniLine( FILELIST *, READPARM *, int, unsigned char *, char * ); int GetGiniHeader( FILELIST *, unsigned char * ); int GetGiniTime( FILELIST *, int *, int *, int * ); int GetInt( unsigned char *, int ); int GiniToMcCal( unsigned char *, int * ); int GiniToMcDir( unsigned char *, int * ); int GiniToMcNav( unsigned char *, int * ); int IsZlibHed( unsigned char * ); int SelectGiniImages( CRITERIA *, FILELIST **, char * ); int TestGiniImages( FILELIST *, FILELIST **, CRITERIA * ); #if UNIDATA Fint4 ispnghed_( unsigned char * ); #endif
/* * Copyright(c) 2004, Space Science and Engineering Center, UW-Madison * Refer to "McIDAS Software Acquisition and Distribution Policies" * in the file mcidas/data/license.txt */ /**** $Id: giniutil.c,v 1.4 2009/11/18 23:06:02 tomy Tst $ ****/ #include <sys/types.h> #include <dirent.h> #include <stdio.h> #include <stdlib.h> #include <strings.h> #include <time.h> #include <sys/stat.h> #include <math.h> #include "mcidas.h" #include "giniutil.h" #if UNIDATA #include "png.h" #endif #include "zlib.h" #include "zutil.h" #define DEBUG_CALIB 0 #define DEBUG_DIRS 0 #define DEBUG_ENTRY 0 #define DEBUG_HEADR 0 #define DEBUG_IMAGE 0 #define DEBUG_LINE 0 #define DEBUG_MCCAL 0 #define DEBUG_MCDIR 0 #define DEBUG_MCNAV 0 #define DEBUG_TEST 0 #define DEBUG_TIME 0 static char dbg[MAX_ERR_LEN]; /* debug message */ /* <<<<< UPC add 20081204 - add needed function prototypes >>>>> */ Fint lit_( const char *, FsLen ); /*************************** CalibrateGiniImgData ****************************/ int CalibrateGiniImgData( int band, int *calcod, unsigned char *data, int nval, char *unit, int size ) /* ** Name: CalibrateGiniImgData ** ** Purpose: Convert GINI data to requested unit in place ** ** Parameters: ** band - band number ** calcod - calibration codicil ** data - buffer of data to calibrate ** nval - number of bytes to convert ** unit - unit to convert to ** size - number of bytes per element to be returned ** ** Returns: ** SUCCESS == 1 ** FAILURE == 0 ** */ { unsigned short *s2; /* pointer to unsigned short */ unsigned short *cal2; /* pointer to calibration array */ int *s4; /* pointer to unsigned short */ int *cal4; /* pointer to calibration array */ int *calblk; /* calibration segments for UNIT */ int i, j, k; /* generic counters */ int ival; /* brightness value as an int */ int minB, maxB; /* min,max calibration BRTI vals */ int ncals; /* # calibration segments */ int dbz; /* echo strength [dbZ] */ int dvip[]={ 0, 30, 40, 45, 50, 55 }; /* DVIP break points */ float *a; /* val = (a * data + b)/s */ float *b; /* val = (a * data + b)/s */ float *s; /* scale factor */ float numer; /* numerator */ float denom; /* denominator */ float scale; /* scale factor from AUX block */ float minval; /* min data val from AUX block */ float maxval; /* max data val from AUX block */ #if DEBUG_ENTRY M0sxtrce( "in CalibrateGiniImgData" ); #endif #if DEBUG_CALIB (void) sprintf( dbg, "CalibrateGiniImgData:: unit: %s band: %d size: %d", unit, band, size ); M0sxtrce( dbg ); #endif /* ** If unit is RAW no calibration is necessary */ if ( !strncmp( unit, "RAW", 3 ) ) { #if DEBUG_CALIB M0sxtrce( "CalibrateGiniImgData:: RAW requires no calibration" ); #endif return SUCCESS; } /* <<<<< UPC mod 20110314 - scale TEMP by 10 to match servutil.c mod >>>>> */ scale = 1.0; if ( !strncmp( unit, "TEMP", 4 ) ) scale = 10.0; /* ** Count all calibration segments for UNIT in calcod */ ncals = 0; for ( i = 0; i < calcod[0]; i++ ) if ( !strncmp( unit, (char *) &calcod[1+(8*i)], strlen(unit) ) ) ncals++; if ( ncals == 0 ) { (void) sprintf( dbg, "CalibrateGiniImgData:: unit: %s ncals: %d", unit, ncals ); M0sxtrce( dbg ); return FAILURE; } /* ** allocate space for cal block for all UNIT cal segments */ calblk = (int *) malloc( ncals * 8 * sizeof(int) + 1 ); if ( calblk == (int *) NULL ) { M0sxtrce( "CalibrateGiniImgData:: calblk malloc error" ); return ERR_STAT_MALLOC; } /* ** copy all UNIT cal segments from calcod to calblk */ calblk[0] = ncals; k = 0; for ( i = 0; i < calcod[0]; i++ ) { if ( !strncmp( unit, (char *) &calcod[1+(8*i)], strlen(unit) ) ) { for ( j = 1; j < 9; j++ ) { calblk[j+(8*k)] = calcod[j+(8*i)]; } k++; } } /* ** Create arrays of transform coefficients: dval = a[i] * ival * b[i] */ a = (float *) malloc( ncals * sizeof(float) ); b = (float *) malloc( ncals * sizeof(float) ); s = (float *) malloc( ncals * sizeof(float) ); if ( a == (float *)NULL || b == (float *)NULL || s == (float *)NULL ) { M0sxtrce( "CalibrateGiniImgData:: transform coefficients malloc error" ); return ERR_STAT_MALLOC; } for ( i = 0; i < ncals; i++ ) { numer = calblk[2+(i*8)] - calblk[3+(i*8)]; denom = calblk[4+(i*8)] - calblk[5+(i*8)]; a[i] = numer / denom; b[i] = calblk[2+(i*8)] - a[i] * calblk[4+(i*8)]; s[i] = calblk[7+(i*8)]; #if DEBUG_CALIB (void) sprintf( dbg, "CalibrateGiniImgData:: i: %d, a[i]: %f, b[i]: %f, s[i]: %f", i, a[i], b[i], s[i] ); M0sxtrce( dbg ); #endif } /* ** Convert raw image data to calibrated unit */ switch ( size ) { case 1: for ( i = 0; i < nval; i++ ) { ival = (int) data[i]; k = -1; for ( j = 0; j < ncals; j++ ) { if ( calblk[4+(j*8)] <= ival && ival <= calblk[5+(j*8)] ) { k = j; #if DEBUG_CALIB (void) sprintf( dbg, "CalibrateGiniImgData:: k: %d, minB: %d ival: %d maxB: %d", k, calblk[4+(j*8)], ival, calblk[5+(j*8)] ); M0sxtrce( dbg ); #endif } } if ( k >= 0 ) data[i] = scale * (a[k] * data[i] + b[k])/s[k]; else data[i] = 0; } break; case 2: (void) sprintf( dbg, "CalibrateGiniImgData:: 2-byte calibration for %s", unit ); M0sxtrce( dbg ); cal2 = (unsigned short *) malloc( nval * sizeof(short) ); if ( cal2 == (unsigned short *) NULL ) { (void) memset( data, 0, nval ); (void) strcat( dbg, "CalibrateGiniImgData:: 2-byte malloc error" ); M0sxtrce( dbg ); return ERR_STAT_MALLOC; } s2 = cal2; for ( i = 0; i < nval; i++ ) { ival = (int) data[i]; k = -1; for ( j = 0; j < ncals; j++ ) { if ( calblk[4+(j*8)] <= ival && ival <= calblk[5+(j*8)] ) { k = j; #if DEBUG_CALIB (void) sprintf( dbg, "CalibrateGiniImgData:: k: %d, minB: %d ival: %d maxB: %d", k, calblk[4+(j*8)], ival, calblk[5+(j*8)] ); M0sxtrce( dbg ); #endif } } if ( k >= 0 ) *s2 = scale * (a[k] * ival + b[k])/s[k]; else *s2 = 0; s2++; } (void) swbyt2_( cal2, &nval ); (void) memcpy( data, cal2, nval * sizeof(short) ); free( cal2 ); break; case 4: (void) sprintf( dbg, "CalibrateGiniImgData:: 4-byte calibration for %s", unit ); M0sxtrce( dbg ); cal4 = (int *) malloc( nval * sizeof(int) ); if ( cal4 == (int *) NULL ) { (void) memset( data, 0, nval ); (void) strcat( dbg, "CalibrateGiniImgData:: 4-byte malloc error" ); M0sxtrce( dbg ); return ERR_STAT_MALLOC; } s4 = cal4; for ( i = 0; i < nval; i++ ) { ival = (int) data[i]; k = -1; for ( j = 0; j < ncals; j++ ) { if ( calblk[4+(j*8)] <= ival && ival <= calblk[5+(j*8)] ) { k = j; #if DEBUG_CALIB (void) sprintf( dbg, "CalibrateGiniImgData:: k: %d, minB: %d ival: %d maxB: %d", k, calblk[4+(j*8)], ival, calblk[5+(j*8)] ); M0sxtrce( dbg ); #endif } } if ( k >= 0 ) *s4 = scale * (a[k] * ival + b[k])/s[k]; else *s4 = 0; #if DEBUG_CALIB (void) sprintf( dbg, "CalibrateGiniImgData:: raw value: ival = %d, calibrated value: *s4 = %d", ival, *s4 ); M0sxtrce( dbg ); #endif s4++; } (void) swbyt4_( cal4, &nval ); (void) memcpy( data, cal4, nval * sizeof(int) ); free( cal4 ); break; default: #if DEBUG_CALIB (void) sprintf( dbg, "CalibrateGiniImgData:: unsupported size type: %d", size ); M0sxtrce( dbg ); #endif return FAILURE; } return SUCCESS; } /******************************* GetGiniDirs *********************************/ int GetGiniDirs( FILELIST *cur, int *aradir, int *navcod, int *calcod, int *auxblk ) /* ** Name: GetGiniDirs ** ** Purpose: Read a GINI file and create corresponding McIDAS area directory ** ** Parameters: ** cur - FILELIST structure containing current image information ** name - full qualified name of the file ** pos - position to add to list ** hoff - byte offset to beginning of image header ** doff - byte offset to beginning of image data ** size - number of lines in Zlib compressed block ** type - file type ** time - file data time [sec since 1970] ** aradir - McIDAS area directory for image ** navcod - McIDAS navigation codicil for image ** calcod - McIDAS calibration codicil for image ** auxblk - McIDAS supplementary block for image ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** ** NOTES: ** The indices for aradir in this function are zero-based. ** */ { unsigned char header[GINI_PDB_LEN]; /* GINI header */ char ctemp[GINI_PDB_LEN]; char cmemo[33]; /* memo field */ char *cmode[]={"Maintenance", "Clear Air", "Precip Mode"}; char ctilt[9]; /* radar tilt or layer */ char ctitle[41]; /* AUX block memo field */ char cunit[9]; /* product data unit */ int auxsiz; /* AUX block size in words */ int update_rate[]={10, 6, 5};/* clear air/precip/storm update */ int levels[256]; int i,j; /* loop variables */ int rc; /* function return status */ int creator; /* Originating center */ int band_id; /* GINI channel ID */ int ncalseg; /* number of calibration segments*/ int nexrcode=0; /* code for equiv. NEXRAD prod. */ int res; /* product resolution [km] */ int min_val; /* product minimum value */ int max_val; /* product maximum value */ int scale; /* data scale factor */ int offset; /* data offset value */ int nlevels; /* number of data levels */ float delta; time_t datetime; /* holds time in seconds */ struct tm settime; /* time structure */ struct tm *crtime; /* time structure pointer */ int day; /* day - DD (e.g. 03) */ int imon; /* month - MMM (e.g. Jan) */ int year; /* year - YY (e.g. 98) */ struct stat file_stat; /* 'stat' information */ FILE *fd; /* file descriptor */ #if DEBUG_ENTRY M0sxtrce( "in GetGiniDirs" ); #endif rc = GetGiniHeader( cur, header ); if ( rc == FAILURE ) { #if DEBUG_DIRS M0sxtrce( "GetGiniDirs: Error reading GINI image header" ); #endif return FAILURE; } /*************************************************************************/ /* AREA directory */ /*************************************************************************/ /* ** Convert the GINI header information to McIDAS AREA file format */ for ( i = 0; i < IMG_DIR_LEN; i++ ) { aradir[i] = 0; } rc = GiniToMcDir( header, aradir ); /* ** Use the file creation time as the image creation time */ (void) stat( cur->name, &file_stat ); datetime = file_stat.st_ctime; crtime = gmtime( &datetime ); aradir[16] = 1000*crtime->tm_year + crtime->tm_yday + 1; aradir[17] = 10000*crtime->tm_hour + 100*crtime->tm_min + crtime->tm_sec; #if DEBUG_DIRS for ( i = 0; i < IMG_DIR_LEN; i++ ) { sprintf(ctemp, "GetGiniDirs:: aradir[%2d]: %d", i, aradir[i] ); M0sxtrce( ctemp ); } #endif cur->size = file_stat.st_size-aradir[9]; /* size of file in bytes less GINI HDR and EOF records */ /*************************************************************************/ /* Navigation Codicil */ /*************************************************************************/ /* ** Create a McIDAS navigation block from the GINI header information */ for ( i = 0; i < NAV_COD_LEN; i++ ) { navcod[i] = 0; } rc = GiniToMcNav( header, navcod ); /*************************************************************************/ /* Calibration Codicil */ /*************************************************************************/ /* ** Convert the GINI header information to McIDAS calibration codicil or ** auxiliary block depending on band. */ for ( i = 0; i < CAL_COD_LEN+1; i++ ) { calcod[i] = 0; } rc = GiniToMcCal( header, calcod ); /*************************************************************************/ /* Auxiliary block */ /*************************************************************************/ for ( i = 0; i < AUX_BLK_LEN; i++ ) { auxblk[i] = 0; } creator = (int) *( header + 1 ); /* <<<<< 20051007 - UPC Add >>>>> */ band_id = (int) *( header + 3 ); #if DEBUG_DIRS (void) sprintf( dbg, "GetGiniDirs:: create entity: %d, band id: %d", creator, band_id ); M0sxtrce( dbg ); #endif res = (int) *( header + 41 ); /* image resolution [km] */ if ( creator != 99 ) { /* NOAAPORT GINI images */ switch ( band_id ) { /* CAL block/AUX block depend on band */ case 0: /* No CAL/AUX block for VIS */ break; case 2: /* CAL block for IR bands */ case 3: case 4: case 5: case 6: /* <<<<< 20051007 - UPC Add >>>>> */ case 7: /* <<<<< 20051007 - UPC Add >>>>> */ aradir[51] = lit_( "PRD ", 4 ); /* PRD calibration */ aradir[62] = aradir[33]; /* start of cal block */ aradir[33] = aradir[62]+4*CAL_COD_LEN; /* start of data block */ break; } } else { /* Unidata NEXRAD Level 3 composite images */ switch ( band_id ) { /* CAL block/AUX block depend on band */ case 26: /* AUX block for NET composite */ (void) sprintf( cmemo, "%d km CONUS NET Composite [K FT]", res ); (void) strcpy( ctilt, "-99" ); (void) strcpy( ctitle, "TOPS: Echo Tops" ); (void) strcpy( cunit, "K FT" ); nexrcode = 41; /* NEXRAD code for Echo Tops */ min_val = calcod[2]; max_val = calcod[3]; scale = calcod[7]; offset = calcod[8]; nlevels = 16; delta = (max_val - min_val) / (nlevels - 2); levels[0] = -9997; levels[1] = min_val; for ( i = 2; i < nlevels; i++ ) { levels[i] = levels[i-1] + delta; } break; case 27: /* AUX block for N0R composite */ case 28: /* AUX block for NCR composite */ case 32: /* AUX block for N0Q composite */ if ( band_id == 27 ) { /* NEXRAD Base Reflectivity N0R */ (void) sprintf( cmemo, "%d km CONUS N0R Composite [dBZ]", res ); (void) strncpy( ctilt, "Tilt 1", 6 ); (void) strcpy( ctitle, "BREF: Base Reflectivity" ); nexrcode = 19; nlevels = 22; } else if ( band_id == 32 ) { /* NEXRAD Base Reflectivity N0Q */ /* <<<<< UPC add 20101119 - for "high resolution" composites >>>>> */ (void) sprintf( cmemo, "%d km CONUS N0Q Composite [dBZ]", res ); (void) strncpy( ctilt, "Tilt 1", 6 ); (void) strcpy( ctitle, "BREF: Base Reflectivity" ); nexrcode = 94; nlevels = 24; } else { /* NEXRAD Comp Reflectivity NCR */ (void) sprintf( cmemo, "%d km CONUS NCR Composite [dBZ]", res ); (void) strcpy( ctilt, "-99" ); (void) strcpy( ctitle, "CREF: Composite Reflectivity" ); nexrcode = 37; nlevels = 22; } (void) strcpy( cunit, "dBZ" ); min_val = calcod[2]; max_val = calcod[3]; scale = calcod[7]; offset = calcod[8]; delta = (float)(max_val - min_val) / (nlevels - 1); levels[0] = min_val; for ( i = 1; i < nlevels; i++ ) { levels[i] = levels[i-1] + delta; } break; case 29: /* AUX block for NVL composite */ (void) sprintf( cmemo, "%d km CONUS NVL Composite [mm]", res ); (void) strcpy( ctilt, "-99" ); (void) strcpy( ctitle, "VIL: Vertically-integrated Liquid Water" ); (void) strcpy( cunit, "kg/m^2" ); nexrcode = 57; /* NEXRAD code for vert liq H2O*/ min_val = calcod[2]; max_val = calcod[3]; scale = calcod[7]; offset = calcod[8]; nlevels = 16; delta = (max_val - min_val) / (nlevels - 1); levels[0] = -9997; levels[1] = 1; for ( i = 2; i < nlevels; i++ ) { levels[i] = delta * (i-1); } break; case 30: /* AUX block for N1P composite */ (void) sprintf( cmemo, "%d km CONUS N1P Composite [IN]", res ); (void) strcpy( ctilt, "-99" ); (void) strcpy( ctitle, "PRE1: Surface 1-hour Rainfall Total" ); (void) strcpy( cunit, "IN" ); nexrcode = 78; /* NEXRAD code for 1-hr Precip */ min_val = 0; max_val = 240; scale = 20; offset = 0; nlevels = 16; delta = (max_val - min_val) / (nlevels - 1); for ( i = 0; i < 8; i++ ) { levels[i] = 5.7143*i; } for ( i = 8; i < 12 ; i++ ) { levels[i] = 40 + 20*(i-7); } for ( i = 12; i < nlevels ; i++ ) { levels[i] = 120 + 30*(i-11); } break; case 31: /* AUX block for NTP composite */ (void) sprintf( cmemo, "%d km CONUS NTP Composite [IN]", res ); (void) strcpy( ctilt, "-99" ); (void) strcpy( ctitle, "PRET: Surface Storm Total Rainfall" ); (void) strcpy( cunit, "IN" ); nexrcode = 80; /* NEXRAD code for Total Precip*/ min_val = 0; max_val = 240; scale = 10; offset = 0; nlevels = 16; delta = (max_val - min_val) / (nlevels - 1); for ( i = 0; i < 8; i++ ) { levels[i] = 5.7143*i; } for ( i = 8; i < 12 ; i++ ) { levels[i] = 40 + 20*(i-7); } for ( i = 12; i < nlevels ; i++ ) { levels[i] = 120 + 30*(i-11); } break; } } if ( nexrcode ) { auxsiz = 43 + nlevels; /* AUX block length in words */ aradir[ 2] = 7; /* Radar */ aradir[20] = lit_( "TWX ", 4 ); /* Closest NEXRAD to center */ aradir[21] = nexrcode; /* NEXRAD code for Echo Tops */ aradir[22] = 2; /* Composites every 5 minutes */ (void) strncpy( (char *) &aradir[24], cmemo, 32 ); aradir[51] = lit_( "NEXR", 4 ); /* source type */ aradir[52] = lit_( "RAW ", 4 ); /* RAW values stored in image */ aradir[56] = 0; aradir[59] = aradir[34]+4*NAV_COD_LEN; /* byte offset to AUX block */ aradir[62] = 0; /* byte offset to cal block */ aradir[60] = 4 * auxsiz; /* AUX block length in bytes */ aradir[33] = aradir[59] + aradir[60]; /* start of data block */ auxblk[ 0] = 0x04030201; /* magic number */ auxblk[ 1] = 4 * auxsiz; /* AUX block size in bytes */ auxblk[ 2] = 4; /* length of entry name in byte*/ auxblk[ 3] = 4 * (auxsiz-5); /* length of entry bytes */ auxblk[ 4] = lit_("INFO",4); /* AUX block name is 'INFO' */ (void) memset( &auxblk[5], ' ', 40 ); /* memo field */ (void) memcpy( &auxblk[5], ctitle, strlen(ctitle) ); auxblk[15] = aradir[21]; /* NEXRAD product code */ auxblk[16] = 8; /* # bytes in radar textual ID */ (void) memset( &auxblk[17], ' ', 8 ); /* radar ID */ (void) memcpy( &auxblk[17], &aradir[20], 4 ); auxblk[19] = navcod[3]; /* radar latitude */ auxblk[20] = navcod[4]; /* radar longitude */ auxblk[21] = 0; /* radar elevation */ auxblk[22] = aradir[3]; /* composite DAY [YYYDDD] */ auxblk[23] = aradir[4]; /* composite TIME [HHMMSS] */ auxblk[24] = 2; /* radar mode */ auxblk[26] = res; /* resolution */ auxblk[25] = 128; /* range */ auxblk[27] = update_rate[aradir[22]]; /* update rate [10|6|5] */ (void) memset( &auxblk[28], ' ', 8 ); /* tilt angle or layer */ (void) memcpy( &auxblk[28], ctilt, strlen(ctilt) ); auxblk[42] = scale; /* data scale */ auxblk[30] = auxblk[42]; /* min/max scale factor */ auxblk[31] = min_val*auxblk[30]; /* min data value */ auxblk[32] = max_val*auxblk[30]; /* max data value */ auxblk[33] = auxblk[22]; /* start DAY [YYYDDD] */ auxblk[34] = auxblk[23]; /* start TIME [HHMMSS] */ auxblk[35] = auxblk[22]; /* end DAY [YYYDDD] */ auxblk[36] = auxblk[23]; /* end TIME [HHMMSS] */ auxblk[37] = 8; /* # bytes in unit */ (void) memset( &auxblk[38], ' ', 8 ); /* data unit */ (void) memcpy( &auxblk[38], cunit, strlen(cunit) ); auxblk[40] = nlevels; /* # data levels */ auxblk[41] = offset; /* data offset */ /* auxblk[42] is scale above */ for ( i = 0; i < auxblk[40]; i++ ) { /* scaled calibrated values */ auxblk[43+i] = levels[i]; } #if DEBUG_DIRS for ( i = 0; i < auxsiz; i++ ) { (void) sprintf( dbg, "GetGiniDirs:: auxblk[%3d] = 0x%08X %2d", i, auxblk[i], auxblk[i] ); M0sxtrce( dbg ); } #endif } else { auxblk[0] = -1; } /* ** Done */ return SUCCESS; } /******************************* GetGiniLine *********************************/ int GetGiniLine( FILELIST *cur, READPARM *read, int band, unsigned char *buf, char *err ) /* ** Name: GetGiniLine ** ** Purpose: Extract a line of data from a GINI image ** ** Parameters: ** cur - FILELIST structure containing current image information ** name - full qualified name of the file ** pos - position to add to list ** hoff - byte offset to beginning of image header ** doff - byte offset to beginning of image data ** size - number of lines in Zlib compressed block ** type - file type ** time - file data time [sec since 1970] ** read - READPARM struct containing read specs ** band - band number of elements to read ** buf - buffer containing image data ** err - error string to return ** ** Returns: ** SUCCESS == 1 ** FAILURE == 0 ** ** History: 19980320 - Shamelessly adapted from a combination of SSEC example ** ADDE server code (MUG training set) ** 20030713 - Added support for Zlib compressed image read ** */ { static unsigned char *lbuf=NULL; /* input line buffer */ static unsigned char *p; /* input line buffer pointer */ static int eof=0; /* end of data indicator */ static int lastline=0; /* last line of file read */ static FILE *fd; /* file descriptor */ int nline=0; int rc; static size_t lsize; /* size of line input buffer */ static size_t nmove=0; /* # bytes to move in buffer */ static size_t nread; /* # bytes to read */ #if UNIDATA static int png_blin = -1; /* PNG buffer beginning line */ static int png_elin = -1; /* PNG buffer ending line */ static png_structp png_ptr; #endif static unsigned char zbuf[GINI_ZBUF_LEN];/* Zlib read buffer */ static int z_blin = -1; /* Zlib buffer beginning line */ static int z_elin = -1; /* Zlib buffer ending line */ static z_stream d_stream; /* Zlib decompression stream */ #if DEBUG_LINE M0sxtrce( "in GetGiniLine" ); #endif /* ** If have not already done so, open the data file 'cur->name' */ if ( lbuf == (unsigned char *) NULL ) { /* ** Allocate input buffer large enough to hold line of maximum length ** <<<<< UPC mod 20110307 - change size of lbuf to MAX_LINE_LEN >>>>> */ if ( read->maxele > MAX_LINE_LEN ) { (void) sprintf( dbg, "GetGiniLine:: Unreasonable image line length %4d", read->maxele ); M0sxtrce( dbg ); (void) strcpy( err, "Unreasonable image line length" ); return ERR_STAT_BADLINE; } lsize = MAX_LINE_LEN; lbuf = (unsigned char *) malloc( lsize ); if ( lbuf == (unsigned char *) NULL ) { (void) sprintf( dbg, "GetGiniLine:: Unable to malloc %d bytes", lsize ); M0sxtrce( dbg ); (void) strcpy( err, "Unable to allocate memory" ); return ERR_STAT_MALLOC; } /* ** Open image file and set location of first line in file */ fd = fopen ( cur->name, "rb" ); if ( fd == (FILE *) NULL ) { (void) sprintf( dbg, "GetGiniLine:: Unable to open input image" ); M0sxtrce( dbg ); (void) strcpy( err, "Unable to open input image" ); return FAILURE; } #if DEBUG_LINE (void) sprintf( dbg, "GetGiniLine:: cur->hoff = %4d, cur->doff = %4d in %s", cur->hoff, cur->doff, cur->name ); M0sxtrce( dbg ); #endif if ( fseek( fd, (long) cur->doff, SEEK_SET ) ) { (void) sprintf( dbg, "GetGiniLine:: Unable to seek to line" ); M0sxtrce( dbg ); (void) strcpy( err, "Unable to seek to data in input image" ); (void) fclose( fd ); return FAILURE; } if ( cur->type == 1 ) { (void) sprintf( dbg, "GetGiniLine:: read %4d Zlib compressed bytes", GINI_ZBUF_LEN ); M0sxtrce( dbg ); nread = fread( zbuf, (size_t) 1, (size_t) GINI_ZBUF_LEN, fd ); if ( nread != GINI_ZBUF_LEN ) { (void) sprintf( dbg, "GetGiniLine:: Unable to read Zlib buffer" ); M0sxtrce( dbg ); (void) strcpy( err, "Error reading input image" ); (void) fclose( fd ); return FAILURE; } d_stream.zalloc = (alloc_func) 0; d_stream.zfree = (free_func) 0; d_stream.opaque = (voidpf) 0; d_stream.next_in = (Bytef *) zbuf; d_stream.avail_in = (uInt) nread; d_stream.next_out = lbuf; d_stream.avail_out = (uInt) lsize; if ( inflateInit( &d_stream ) != Z_OK ) { M0sxtrce( "GetGiniLine:: Zlib inflateInit error" ); return FAILURE; } rc = inflate( &d_stream, Z_NO_FLUSH ); if ( rc != Z_OK && rc != Z_STREAM_END ) { M0sxtrce( "GetGiniLine:: Zlib inflate error" ); return FAILURE; } cur->size = d_stream.total_out / read->maxele; z_blin = 0; z_elin = cur->size - 1; nmove = nread - d_stream.total_in; nread = d_stream.total_in; #if UNIDATA } else if ( cur->type == 2 ) { int bit_depth = 8; int color_type = PNG_COLOR_TYPE_GRAY; int interlace_type = PNG_INTERLACE_NONE; int compression_type = PNG_COMPRESSION_TYPE_DEFAULT; int filter_type = PNG_FILTER_TYPE_DEFAULT; int nbytes; png_uint_32 lines; png_uint_32 elems; png_infop info_ptr; png_infop end_info; (void) sprintf( dbg, "GetGiniLine:: process png compressed bytes" ); M0sxtrce( dbg ); /* ** Setup PNG pointers, etc. */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if ( !png_ptr ) { (void) strcpy( err, "Error creating PNG read structure" ); (void) fclose( fd ); return FAILURE; } info_ptr = png_create_info_struct( png_ptr ); end_info = png_create_info_struct( png_ptr ); if ( !info_ptr ) { png_destroy_write_struct( &png_ptr, (png_infopp) NULL ); (void) strcpy( err, "Error creating PNG info structure" ); (void) fclose( fd ); return FAILURE; } if ( setjmp(png_ptr->jmpbuf) ) { png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); (void) strcpy( err, "Error setting jump in PNG image" ); (void) fclose( fd ); return FAILURE; } png_init_io( png_ptr, fd ); /* ** Read the PNG informational header */ png_read_info( png_ptr, info_ptr ); png_get_IHDR( png_ptr, info_ptr, &elems, &lines, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type ); #if DEBUG_LINE (void) sprintf( dbg, "GetGiniLine:: lines,elems: %dx%d", lines, elems ); M0sxtrce( dbg ); #endif } #endif } /* ** Check to see if we have already gotten to the EOF or if the requested ** line is past the end of file */ if ( eof ) { (void) sprintf( dbg, "GetGiniLine:: already at EOF" ); M0sxtrce( dbg ); (void) memset( buf, (int) 0, (size_t) read->maxele ); (void) strcpy( err, "Already at EOF" ); return ERR_STAT_BADLINE; } if ( read->beglin >= read->maxlin ) { (void) sprintf( dbg, "GetGiniLine:: read is past EOF" ); M0sxtrce( dbg ); eof = 1; (void) memset( buf, 0, (size_t) read->maxele ); (void) strcpy( err, "Read is past EOF" ); return ERR_STAT_BADLINE; } /* ** Read in the requested line */ #if DEBUG_LINE (void) sprintf( dbg, "GetGiniLine:: beglin: %d lline: %d mele: %d bele: %d", read->beglin, lastline, read->maxele, read->begele ); M0sxtrce( dbg ); #endif switch ( cur->type ) { case 0: /* Uncompressed images */ (void) sprintf( dbg, "GetGiniLine:: read uncompressed image line %d", lastline ); M0sxtrce( dbg ); { long offset = (read->beglin - lastline) * read->maxele; if ( fseek( fd, offset, SEEK_CUR ) ) { (void) sprintf( dbg, "GetGiniLine:: error seeking to offset: %ld", offset ); M0sxtrce( dbg ); (void) memset( buf, 0, (size_t) read->maxele ); (void) strcpy( err, "Unable to seek to data" ); return ERR_STAT_SEEK; } if ( !fread( lbuf, (size_t) read->maxele, (size_t) 1, fd ) ) { (void) sprintf( dbg, "GetGiniLine:: error reading file: %d", read->maxele ); M0sxtrce( dbg ); return ERR_STAT_BADLINE; } p = lbuf; lastline = read->beglin + 1; } break; case 1: /* Zlib-compressed images */ (void) sprintf( dbg, "GetGiniLine:: read Zlib-compressed image line %d", lastline ); M0sxtrce( dbg ); #if DEBUG_LINE (void) sprintf( dbg, "GetGiniLine:: read->beglin = %4d, z_elin = %4d", read->beglin, z_elin ); M0sxtrce( dbg ); #endif while ( read->beglin > z_elin ) { (void) sprintf( dbg, "GetGiniLine:: nread = %4d, nmove = %4d", nread, nmove ); M0sxtrce( dbg ); (void) memmove( zbuf, zbuf+nread, nmove ); nread = fread( zbuf+nmove, (size_t)1, nread, fd ); if ( ! nread ) { eof = 1; (void) memset( buf, 0, (size_t) read->maxele ); (void) strcpy( err, "Already at EOF" ); return ERR_STAT_BADLINE; } nmove = nmove + nread; d_stream.zalloc = (alloc_func) 0; d_stream.zfree = (free_func) 0; d_stream.opaque = (voidpf) 0; d_stream.next_in = (Bytef *) zbuf; d_stream.avail_in = (uInt) nmove; d_stream.next_out = lbuf; d_stream.avail_out = (uInt) lsize; if ( inflateInit( &d_stream ) != Z_OK ) { M0sxtrce( "GetGiniLine:: Zlib inflateInit error" ); return FAILURE; } rc = inflate( &d_stream, Z_NO_FLUSH ); if ( rc != Z_OK && rc != Z_STREAM_END ) { M0sxtrce( "GetGiniLine:: Zlib inflate error" ); return FAILURE; } /* ** Sanity check. Make sure number of lines in output buffer is consistent. */ nline = d_stream.total_out / read->maxele; if ( nline != cur->size ) { eof = 1; (void) sprintf( dbg, "GetGiniLine:: line size mismatch wanted %2d got %2d", cur->size, nline ); M0sxtrce( dbg ); (void) memset( buf, 0, (size_t) read->maxele ); (void) strcpy( err, "Already at EOF" ); return ERR_STAT_BADZBLOK; } nread = d_stream.total_in; nmove -= d_stream.total_in; z_blin = z_elin + 1; z_elin = z_blin + cur->size - 1; (void) sprintf( dbg, "GetGiniLine:: z_blin = %4d, z_elin = %4d", z_blin, z_elin ); M0sxtrce( dbg ); } p = (read->beglin - z_blin) * read->maxele + lbuf; break; #if UNIDATA case 2: /* Unidata PNG-compressed images */ (void) sprintf( dbg, "GetGiniLine:: read PNG-compressed image line %d", lastline ); M0sxtrce( dbg ); while ( read->beglin > png_elin ) { png_read_row( png_ptr, (png_bytep) lbuf, NULL ); png_elin++; } p = lbuf; break; #endif default: (void) sprintf( dbg, "GetGiniLine:: unrecognized image type %d", cur->type ); M0sxtrce( dbg ); return ERR_STAT_SELECT; } /* ** Copy the desired portion of the line to the output buffer and return */ #if DEBUG_LINE (void) sprintf( dbg, "GetGiniLine:: copied %d elements into line buffer", read->maxele-read->begele ); M0sxtrce( dbg ); #endif (void) memcpy( buf, p+read->begele, read->maxele-read->begele ); return SUCCESS; } /******************************* GetGiniTime *********************************/ int GetGiniTime( FILELIST *cur, int *date, int *time, int *ss ) /* ** Name: GetGiniTime ** ** Purpose: Get the time of the current Gini image ** ** Note: This routine reads image data from a copyrighted WSI NOWrad ** formatted file. This format is proprietary to WSI Corp. and ** is not for redistribution. No portion of this code may be ** redistributed. ** ** Parameters: ** cur - FILELIST structure containing current image information ** name - full qualified name of the file ** pos - position to add to list ** hoff - byte offset to beginning of image header ** doff - byte offset to beginning of image data ** size - number of lines in Zlib compressed block ** type - file type ** time - file data time [sec since 1970] ** date - image date [CCYYDDD] ** time - image time [HHMMSS] ** ss - image sensor source (=10) ** ** Returns: ** SUCCESS == 1 ** FAILURE == 0 ** */ { unsigned char header[GINI_PDB_LEN]; /* GINI file header */ int aradir[IMG_DIR_LEN]; /* AREA file header */ int rc; /* function return status */ /* <<<<< UPC mod 20071025 - use tsec to get seconds since 19700101 >>>>> */ int tsec; /* seconds since Jan 1 1970 */ #if DEBUG_ENTRY M0sxtrce( "in GetGiniTime" ); #endif rc = GetGiniHeader( cur, header ); if ( rc == FAILURE ) { #if DEBUG_TIME M0sxtrce( "GetGiniTime: Error reading GINI image header" ); #endif return FAILURE; } /* ** Synthesize the AREA header */ rc = GiniToMcDir( header, aradir ); *ss = aradir[2]; *date = aradir[3]; *time = aradir[4]; /* ** Calculate image time */ /* <<<<< UPC mod 20071025 - use tsec to get seconds since 19700101 >>>>> */ rc = Mcdaytimetosec( *date, *time, &tsec ); cur->time = (time_t) tsec; return SUCCESS; } /***************************** SelectGiniImages ******************************/ int SelectGiniImages( CRITERIA *request, FILELIST **satisfy, char *err) /* ** Name: SelectGiniImages ** ** Purpose: Return a list of GINI images ** ** Parameters: ** request - request criteria ** satisfy - list of files that satisfy criteria ** err - textual error message ** ** Returns: ** SUCCESS 1 ** */ { int ALL=lit_( "ALL ", 4 ); /* select all images in dir */ int curpos=0; /* initial position number */ int rc; /* function return status */ time_t dtime=0; /* data time [sec since 1970] */ FILELIST list={0}; /* local FILELIST object */ FILELIST *head=NULL; /* list of files in directory */ FILELIST *cur=NULL; /* list of files in directory */ FILELIST *rawlist=NULL; /* list of files in directory */ FILELIST *test=NULL; /* list of files to test */ FILELIST *timlist=NULL; /* list of time ordered files */ #if DEBUG_ENTRY M0sxtrce( "in SelectGiniImages" ); #endif /* ** The integer representation of 'ALL ' means get all the images in dir */ M0swbyt4( &ALL, 1 ); /* ** Generate a list of files whose names match 'request->filemask' in ** all directories under 'dir'. */ rc = GetFileList( request, &rawlist ); if ( rc == FAILURE ) { (void) sprintf( err, "error generating list of files" ); return FAILURE; } /* ** Test images found to see if they match the patterns in 'request'. ** Add those that match to the renumbered list 'head'. */ rc = TestGiniImages( rawlist, &head, request ); if ( rc == FAILURE ) { (void) strcpy( err, "SelectGiniImages:: TestGiniImages memory allocation error" ); return FAILURE; } /* ** Create the return list of files */ if ( request->bpos == ALL ) { /* ALL files requested */ M0sxtrce( "SelectGiniImages:: ALL files requested" ); *satisfy = head; } else if ( request->bpos > 0 ) { /* absolute positions requested */ M0sxtrce( "SelectGiniImages:: absolute file positions" ); while ( head != NULL ) { /* ** Pop a file off of the stack and check position */ rc = PopFile( &list, &head ); if (list.pos < request->bpos || list.pos > request->epos) continue; /* ** Push file that passes test onto new 'test' stack */ rc = PushFileByName( &list, &test ); if ( rc == FAILURE ) { (void) strcpy( err, "Unable to allocate memory" ); return FAILURE; } } *satisfy = test; } else if ( request->bpos <= 0 ) { /* time relative file positions */ M0sxtrce( "SelectGiniImages:: relative file positions" ); cur = head; while ( cur != NULL ) { /* Reorder by time */ rc = PushFileByTime( cur, &test ); cur = cur->next; } curpos = 1; while ( test != NULL ) { /* pop file; check pos, push */ /* ** Decrement time dependent position */ curpos--; /* ** Pop a file off of the stack and check position */ rc = PopFile( &list, &test ); if (curpos > request->bpos || curpos < request->epos) continue; /* ** Push file that passes test onto new 'timlist' stack */ rc = PushFileByTime( &list, &timlist ); if ( rc == FAILURE ) { (void) strcpy( err, "Unable to allocate memory" ); return FAILURE; } } *satisfy = timlist; } return SUCCESS; } /****************************** TestGiniImages *******************************/ int TestGiniImages( FILELIST *oldlist, FILELIST **newlist, CRITERIA *request ) /* ** Name: TestGiniImage ** ** Purpose: Test an image against the specification criteria detailed ** in struct request ** ** Parameters: ** oldlist - FILELIST structure containing current image information ** name - full qualified name of the file ** pos - position to add to list ** hoff - byte offset to beginning of image header ** doff - byte offset to beginning of image data ** size - number of lines in Zlib compressed block ** type - file type ** time - file data time [sec since 1970] ** newlist - FILELIST list of images satisfing 'request' criteria ** name - full qualified name of the file ** pos - position to add to list ** hoff - byte offset to beginning of image header ** doff - byte offset to beginning of image data ** size - number of lines in Zlib compressed block ** type - file type ** time - file data time [sec since 1970] ** request - CRITERIA to test name ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** ** NOTES: ** No tests will be performed for CRITERIA values of -1 ** */ { int curpos=0; int imgday; /* image day [CCYYDDD] */ int imgss; /* satellite id for image */ int imgtim; /* image time [HHMMSS] */ int rc; /* function status */ FILELIST *cur; /* current element of 'oldlist' */ FILELIST *old; /* previous element of 'oldlist' */ FILELIST *last; /* previous element of 'newlist' */ FILELIST *next; /* next element of 'newlist' */ FILELIST *this; /* current element of 'newlist' */ #if DEBUG_ENTRY M0sxtrce( "in TestGiniImages" ); #endif /* ** Loop through input list of images and create an ouput list ** that has only ones that meet 'request' criteria */ cur = oldlist; while ( cur != (FILELIST *) NULL ) { curpos++; /* ** Get a McIDAS date, time, and sensor source information for this image */ rc = GetGiniTime( cur, &imgday, &imgtim, &imgss ); if ( rc == FAILURE ) { old = cur; cur = cur->next; free( old ); continue; } /* ** Test beginning and ending time */ if ( request->begtim >= 0 ) { if (imgtim < request->begtim || imgtim > request->endtim) { M0sxtrce( "TestGiniImages:: fails begin/end time test" ); old = cur; cur = cur->next; free( old ); continue; } } /* ** Test beginning and ending day */ if ( request->begday >= 0 ) { if (imgday < request->begday || imgday > request->endday) { M0sxtrce( "TestGiniImages:: fails begin/end day test" ); old = cur; cur = cur->next; free( old ); continue; } } /* ** Test beginning and ending McIDAS ss number */ if ( request->begss >= 0 ) { if (imgss < request->begss || imgss > request->endss) { M0sxtrce( "TestGiniImages:: fails begin/end SS test" ); old = cur; cur = cur->next; free( old ); continue; } } /* ** At this point, we have an image that meets all 'request' ** criteria. */ cur->pos = curpos; if ( *newlist == (FILELIST *) NULL ) { /* output list is empty */ *newlist = cur; } else { last->next = cur; } last = cur; cur = cur->next; last->next = (FILELIST *) NULL; } /* ** Done */ return SUCCESS; } /********************************** GetInt ***********************************/ int GetInt( unsigned char *ptr, int num ) /* ** Name: GetInt ** ** Purpose: Convert GINI 2, 3, or 4-byte quantities to 4-byte int ** ** Parameters: ** ptr - pointer to first header element of sequence ** num - number of bytes in quantity to convert ** ** Returns: ** integer represented by byte sequence ** ** History: ???????? - Create by SSEC for GINI to AREA file converter ** 19991022 - Adapted for GINI ADDE 'ADIR' and 'AGET' servers ** 20001011 - Changed way 'word' is calculated; incorrect ** values were being generated under SC5.0 x86 C ** */ { unsigned char octet[4]; /* <<<<< UPC mod 20080830 - 3 -> 4 >>>>> */ int base=1; int i; int word=0; #if DEBUG_TEST (void) sprintf( dbg, "In GetInt:: num = %d", num ); M0sxtrce( dbg ); #endif /* ** Make a local copy of the byte sequence */ (void) memcpy( octet, ptr, num ); /* ** Check MSBit: if set, the number is negative */ if ( *octet > 127 ) { *octet -= 128; base = -1; } /* ** Calculate the integer value of the byte sequence */ for ( i = num-1; i >= 0; i-- ) { word += base * octet[i]; base *= 256; #if DEBUG_TEST (void) sprintf( dbg, "GetInt:: octet = %d, word = %d", octet[i], word ); M0sxtrce( dbg ); #endif } /* ** Done */ return word; } /******************************* GiniToMcNav *********************************/ int GiniToMcNav( unsigned char *header, int *navcod ) /* ** Name: GiniToMcNav ** ** Purpose: Convert GINI navigation McIDAS format ** ** Parameters: ** header - GINI format PDB header (521 bytes) ** mcdir - McIDAS navigation codicil ** ** Reference: ** Interface Control Document (ICD) ** for ** AWIPS-National Environmental Satellite, Data and ** Information Service (NESDIS) ** ** AA0130008 CH-2 ** August 1, 1999 ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** ** History: ???????? - Create by SSEC for GINI to AREA file converter ** 19990927 - Adapted for GINI ADDE 'ADIR' and 'AGET' servers ** */ { int proj; /* projection type indicator */ /* 1 - Mercator */ /* 3 - Lambert Conf./Tangent Cone*/ /* 5 - Polar Stereographic */ int sat_id; /* GINI creation entity */ int sec_id; /* GINI sector ID */ int sss_id; /* GINI channel ID */ int nx; int ny; int one=1; int pole; double lonv; /* meridian parallel to y-axis */ double mrad; /* map radius */ double dx, dy; double imgres; double xdist; double ydist; double diff_lon; double image_scale; double lat1, lat2; double lon1, lon2; double lat_s; /* McIDAS standard latitude */ double lat_t; /* lat. where res. is 'imgres' */ double colat_t; double colat_1; double Kexp; double temp; double lin_0; /* line of pole */ double ele_0; /* element of pole */ double lin_e; /* image line over equator */ double ele_e; /* image element over equator */ float rlon_v; float rlat_s; float rlon_c; #if DEBUG_ENTRY M0sxtrce( "in GiniToMcNav" ); #endif sat_id = (int) *( header + 1 ); sec_id = (int) *( header + 2 ); sss_id = (int) *( header + 3 ); proj = (int) *( header + 15 ); #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: creating entity= %d", sat_id ); M0sxtrce( dbg ); (void) sprintf( dbg, "GiniToMcNav:: sector id= %d", sec_id ); M0sxtrce( dbg ); (void) sprintf( dbg, "GiniToMcNav:: map projection id= %d", proj ); M0sxtrce( dbg ); #endif /* ** Get grid dimensions */ nx = GetInt( header + 16, 2 ); ny = GetInt( header + 18, 2 ); /* ** Get the image resolution. */ imgres = (int) header[41]; /* Res [km] */ #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: image resolution [km]: %f", imgres ); M0sxtrce( dbg ); (void) sprintf( dbg, "GiniToMcNav:: # points:: x-dir: %d y-dir: %d", nx, ny ); M0sxtrce( dbg ); #endif switch( proj ) { case 1: /* Mercator */ #if DEBUG_MCNAV M0sxtrce( "GiniToMcNav:: MERC projection" ); #endif /* ** Get the latitude and longitude of first and last "grid" points */ lat1 = ((double) GetInt( header+20, 3 )) / 10000.0; lon1 = ((double) GetInt( header+23, 3 )) / 10000.0; lon1 *= -1; #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: lat1: %f lon1: %f", lat1, lon1 ); M0sxtrce( dbg ); #endif lat2 = ((double) GetInt( header+27, 3 )) / 10000.0; lon2 = ((double) GetInt( header+30, 3 )) / 10000.0; lon2 *= -1; #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: lat2: %f lon2: %f", lat2, lon2 ); M0sxtrce( dbg ); #endif /* ** Hack to catch incorrect sign of lon2 in header. */ if ( lon1 > 0.0 && lon2 < 0.0 ) lon2 *= -1; /* ** Get the "Latin" parameter. The ICD describes this value as: ** "Latin - The latitude(s) at which the Mercator projection cylinder ** intersects the earth." It should read that this is the latitude ** at which the image resolution is that defined by octet 41. */ lat_t = ((double) GetInt( header+38, 3 )) / 10000.0; #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: lat_t: %f", lat_t ); M0sxtrce( dbg ); #endif lat_s = 0.0; /* ** Experimentation has shown that ** the "standard latitude" for the ** McIDAS MERCator navigation must ** be zero. */ /* ** Equation for the line at the equator is a result of reverse ** engineering the McIDAS MERC nav module, nvxmerc.dlm. Apparently, ** this formulation allows for oblique Mercator projections. The ** "standard latitude" called for in nvxmerc.dlm appears to be the ** rotation of the projection cylinder for oblique projections. */ /* ** Calculate the spacing needed by the MERCator navigation module */ dy = EARTH_RAD_METERS * cos(DEG_TO_RAD*lat_s) / (ny - 1); dy *= ( log( tan(DEG_TO_RAD*( (lat2-lat_s)/2.0 + 45.0 ) ) ) -log( tan(DEG_TO_RAD*( (lat1-lat_s)/2.0 + 45.0 ) ) ) ); #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: spacing at standard latitude: %f", dy ); M0sxtrce( dbg ); #endif /* ** Compute the line and element of the equator */ lin_e = ny + EARTH_RAD_METERS * cos(DEG_TO_RAD*lat_s) / dy * log( tan( DEG_TO_RAD*(45.0 + (lat1-lat_s)/2.0) ) ); ele_e = (nx - 1) / 2.0; #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: lin_e: %f ele_e: %f", lin_e, ele_e ); M0sxtrce( dbg ); #endif #if 0 dy = 1000.0 * imgres / cos( DEG_TO_RAD*lat_t); /* spacing [m] */ dx = DEG_TO_RAD * EARTH_RAD_METERS * (lon1-lon2) / (ny-1); lin_e = EARTH_RAD_METERS * cos(DEG_TO_RAD*lat_t) / dy * log( tan( DEG_TO_RAD*(45.0 + lat2/2.0) ) ) - 42000./dy; #endif /* ** Compute the longitude of the center of the image */ if ( lon1 < 0 ) lon1 += 360.0; if ( lon2 < 0 ) lon2 += 360.0; rlon_c = lon1 - (lon1 - lon2) / 2.0; if ( rlon_c > 180.0 ) rlon_c -= 360.0; if ( rlon_c < -180.0 ) rlon_c += 360.0; /* ** Convert the standard latitude and normal longitude to reals ** for use in the Fortran LALO function. */ rlat_s = lat_s; /* ** Set the values in the navigation block */ navcod[0] = lit_( "MERC", 4 ); /* MERC navigation module */ navcod[1] = (int) imgres * lin_e; /* image line of the equator */ navcod[2] = (int) imgres * ele_e; /* image element of the equator */ navcod[3] = ilalo_( &rlat_s ); /* std. latitude [DDDMMSS] */ navcod[4] = (int) dy / imgres; /* spacing at std. lat. [m] */ navcod[5] = ilalo_( &rlon_c ); /* normal longitude [DDDMMSS] */ navcod[6] = EARTH_RAD_METERS; /* Earth radius [m] */ navcod[7] = EARTH_ECCENTRICITY; /* eccentricity * 1000000 */ navcod[8] = 0; /* coord type >=0 -> planetodetic*/ navcod[9] = 0; /* long. conv. >=0 -> west pos. */ break; case 3: /* Tangent Cone */ case 5: /* Polar Stereographic */ #if DEBUG_MCNAV if ( proj == 3 ) { M0sxtrce( "GiniToMcNav:: TANC projection" ); } else { M0sxtrce( "GiniToMcNav:: PS projection" ); } #endif /* ** Check high bit of octet for North or South projection center */ pole = ( header[36] > 127 ) ? -1 : 1; /* ** Compute McIDAS line/element of projection pole. */ /* ** Get lat/lon of first grid point */ lat1 = ((double) GetInt( header+20, 3 )) / 10000.0; lon1 = ((double) GetInt( header+23, 3 )) / 10000.0; #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: 1st point:: lat: %f lon: %f", lat1, lon1 ); M0sxtrce( dbg ); #endif /* ** Get distance increment of grid */ dx = ((double) GetInt( header+30, 3 )) / 10.; dy = ((double) GetInt( header+33, 3 )) / 10.; #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: dist inc x-dir: %f y-dir: %f", dx, dy ); M0sxtrce( dbg ); #endif if ( proj == 5 ) { lat_t = 60.0; /* Fixed for polar stereographic */ image_scale = (1. + sin(DEG_TO_RAD*lat_t))/ (1. + sin(DEG_TO_RAD*lat1)); mrad = EARTH_RAD_METERS * image_scale * cos(DEG_TO_RAD*lat1); } if ( proj == 3 ) { /** Get tangent latitude **/ lat_t = ((double) GetInt( header+38, 3 )) / 10000.0; colat_t = 90. - lat_t; colat_1 = 90. - lat1; Kexp = cos(DEG_TO_RAD*colat_t); temp = tan(DEG_TO_RAD*colat_1*0.5)/tan(DEG_TO_RAD*colat_t*0.5); mrad = EARTH_RAD_METERS * tan(DEG_TO_RAD*colat_t) * pow(temp,Kexp); #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: standard latitude %f", lat_t ); M0sxtrce( dbg ); (void) sprintf( dbg, "GiniToMcNav:: colat_t %f colat_1 %f", colat_t, colat_1 ); M0sxtrce( dbg ); (void) sprintf( dbg, "GiniToMcNav:: Kexp %f temp %f mrad %f", Kexp, temp, mrad ); M0sxtrce( dbg ); #endif } /* ** Get normal longitude */ lonv = ((double) GetInt( header+27, 3 )) / 10000.0; #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: lon parallel to y-axis (lov): %f", lonv ); M0sxtrce( dbg ); #endif if ( sec_id == 10 ) { #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: change lov from %f to 255.0000", lonv ); M0sxtrce( dbg ); #endif lonv = 255.0; } /* Convert to east longitude */ if ( lonv < 0. ) lonv += 360.; if ( lon1 < 0. ) lon1 += 360.; diff_lon = lonv - lon1; if ( diff_lon > 180. ) diff_lon -= 360.; if ( diff_lon < -180. ) diff_lon += 360.; #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: diff_lon %f", diff_lon ); M0sxtrce( dbg ); #endif if ( diff_lon > 0 ) { /* grid origin west of lonv */ if ( proj == 3 ) diff_lon = Kexp*diff_lon; /* Tangent Cone */ xdist = mrad * sin(DEG_TO_RAD*diff_lon); ydist = mrad * cos(DEG_TO_RAD*diff_lon); ele_0 = 1 + xdist/dx; lin_0 = 1 - (ydist/dy - ny); #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: x %f %f %f", xdist, dx, ele_0 ); M0sxtrce( dbg ); (void) sprintf( dbg, "GiniToMcNav:: y %f %f %f", ydist, dy, lin_0 ); M0sxtrce( dbg ); #endif } if ( diff_lon < 0 ) { /* grid origin east of lonv */ /** This section is incomplete **/ xdist = mrad*sin(-DEG_TO_RAD*diff_lon); ydist = mrad*cos(-DEG_TO_RAD*diff_lon); ele_0 = 1 + xdist/dx; lin_0 = 1 - (ydist/dy - ny); #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: lin,ele %f %f",lin_0,ele_0 ); M0sxtrce( dbg ); #endif } /* ** Convert to normal longitude to McIDAS convention */ lonv = (lonv > 180.) ? (360.-lonv) : -lonv; #if DEBUG_MCNAV (void) sprintf( dbg, "GiniToMcNav:: lonv %f",lonv ); M0sxtrce( dbg ); #endif rlon_v = lonv; rlat_s = lat_t; if ( proj == 3 ) { navcod[ 0] = lit_( "TANC", 4 ); /* Tangent Cone */ navcod[ 1] = (int) imgres * (lin_0*10000); /* LIN of pole *10000 */ navcod[ 2] = (int) imgres * (ele_0*10000); /* ELE of pole *10000 */ navcod[ 3] = dx * 10. / imgres; /* km/pixel *10000 */ navcod[ 4] = (int) (lat_t * 10000); /* Std. lat. *10000 */ navcod[ 5] = (int) (lonv * 10000); /* Std. lon. *10000 */ } else { navcod[ 0] = lit_( "PS ", 4 ); /* PS -> Polar Stereo. */ navcod[ 1] = (int) imgres * lin_0; /* image LIN of pole */ navcod[ 2] = (int) imgres * ele_0; /* image ELE of pole */ navcod[ 3] = ilalo_( &rlat_s ); /* Std. lat [DDDMMSS] */ navcod[ 4] = dx / imgres; /* Space @ std lat [m] */ navcod[ 5] = ilalo_( &rlon_v ); /* Std. lon [DDDMMSS] */ navcod[ 6] = EARTH_RAD_METERS; /* Earth Radius [m] */ navcod[ 7] = EARTH_ECCENTRICITY; /* Eccentricity*1000000*/ navcod[ 8] = 0; /* Planetodetic */ navcod[ 9] = 0; /* West is positive */ navcod[10] = pole * 900000; /* Pole proj. lat. */ } break; default: return FAILURE; } /* ** Done */ return SUCCESS; } /******************************* GiniToMcDir *********************************/ int GiniToMcDir( unsigned char *header, int *mcdir ) /* ** Name: GiniToMcDir ** ** Purpose: Convert a GINI file header to a McIDAS AREA directory ** ** Parameters: ** header - GINI format PDB header (521 bytes) ** mcdir - McIDAS AREA directory ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** ** History: ???????? - Create by SSEC for GINI to AREA file converter ** 19990927 - Adapted for GINI ADDE 'ADIR' and 'AGET' servers ** */ { char cmemo[80]; /* AREA directory memo field */ int ccyyddd; /* Julian date [CCYYDDD] */ int time; /* Time [HHMMSS] */ int year; /* Year [YY] */ int mon; /* Month of Year */ int day; /* Day of Month */ int hour; /* Hour of Day */ int min; /* Minute of Hour */ int sec; /* Second of Minute */ int rc; /* Function return code */ int sat_id; /* GINI creation entity */ int sec_id; /* GINI sector ID */ int sss_id; /* GINI channel ID */ static int one=1; #if DEBUG_ENTRY M0sxtrce( "in GiniToMcDir" ); #endif /* ** Set some AREA directory constant values */ mcdir[0] = 0; /* relative ADDE dset pos */ mcdir[1] = 4; /* always 4 */ /* ** Create a sensor source number based on creation entity and channel ID ** ** GINI Physical Element/Channel ID ** ** 1 0.65 micron VIS ** 2 3.9 micron Short IR ** 3 6.7 micron WV ** 6.5 micron WV ** 4 10.7 micron Thermal IR ** 5 12.0 micron Long IR ** 6 13.3 micron CO2 ** 7 1.3 micron IR ** 8 Reserved ** ... ** 12 Reserved ** 20 Derived products ** ... ** 25 Derived products ** 40 Reserved ** 41 14.71 micron sounder image ** 42 14.37 micron sounder image ** 43 14.06 micron sounder image ** 44 13.64 micron sounder image ** 45 13.37 micron sounder image ** 46 12.66 micron sounder image ** 47 12.02 micron sounder image ** 48 11.03 micron sounder image ** 49 9.71 micron sounder image ** 50 7.43 micron sounder image ** 51 7.02 micron sounder image ** 52 6.51 micron sounder image ** 53 4.57 micron sounder image ** 54 4.52 micron sounder image ** 55 4.45 micron sounder image ** 56 4.13 micron sounder image ** 57 3.98 micron sounder image ** 58 3.75 micron sounder image ** 59 visible sounder image ** ** Unidata NEXRAD Level III Composite Images (sat_id=99) ** ** 25 2 km National N0Z 248 nm Base Composite Reflectivity ** 26 4 km National NET Echo Tops ** 27 1 km National N0R Base Reflectivity Composite ** 28 1 km National NCR Composite Reflectivity ** 29 4 km National NVL Vertically Integrated Liquid Water ** 30 2 km National N1P 1-hour Precipitation ** 31 4 km National NTP Storm Total Precipitation ** 32 1 km National N0Q Base Reflectivity Composite */ sat_id = (int) *( header + 1 ); /* GINI creation entity */ sec_id = (int) *( header + 2 ); /* GINI sector ID */ sss_id = (int) *( header + 3 ); /* GINI channel ID */ (void) sprintf( cmemo, "GINI:: Sat %2d SecID %2d ChID %2d", sat_id, sec_id, sss_id ); #if DEBUG_MCDIR (void) sprintf( dbg, "GiniToMcDir:: %s", cmemo ); M0sxtrce( dbg ); #endif switch ( sat_id ) { case 6: /* Composite */ mcdir[2] = 10; break; case 7: /* DMSP */ mcdir[2] = 94; mcdir[56] = lit_( "DMSP", 4 ); break; case 8: /* GMS */ mcdir[2] = 12; mcdir[56] = lit_( "GMS ", 4 ); break; case 9: /* METEOSAT (using 6) */ mcdir[2] = 56; mcdir[56] = lit_( "MSAT", 4 ); break; case 10: /* GOES-7 */ if ( sss_id == 1 ) mcdir[2] = 32; else mcdir[2] = 33; mcdir[56] = lit_( "GOES", 4 ); break; case 11: /* GOES-8 */ case 12: /* GOES-9 */ case 13: /* GOES-10 */ case 14: /* GOES-11 */ case 15: /* GOES-12 */ if ( (sss_id >= 1) && (sss_id <= 7) ) mcdir[2] = 70 + 2*(sat_id-11); else if ( (sss_id >= 13) && (sss_id <= 18) ) mcdir[2] = 0; else if ( (sss_id >= 41) && (sss_id <= 59) ) mcdir[2] = 71 + 2*(sat_id-11); mcdir[56] = lit_( "GVAR", 4 ); break; case 16: /* GOES-13 */ case 17: /* GOES-14 (20051011 guess) */ case 18: /* GOES-15 (20051011 guess) */ if ( (sss_id >= 1) && (sss_id <= 7) ) mcdir[2] = 180 + 2*(sat_id-16); else if ( (sss_id >= 13) && (sss_id <= 18) ) mcdir[2] = 0; else if ( (sss_id >= 41) && (sss_id <= 59) ) mcdir[2] = 181 + 2*(sat_id-16); mcdir[56] = lit_( "GVAR", 4 ); break; case 99: /* Unidata NEXRAD Level III Composite */ mcdir[2] = 7; break; } /* ** Calculate the date from the Year, Month, and Day */ year = (int) *( header + 8 ); year += (year > 70) ? 1900 : 2000; mon = (int) *( header + 9 ); day = (int) *( header +10 ); #if DEBUG_MCDIR (void) sprintf( dbg, "GiniToMcDir:: year: %d mon: %d day: %d", year, mon, day ); M0sxtrce( dbg ); #endif rc = Mcdmytocyd( day, mon, year, &ccyyddd ); mcdir[3] = ccyyddd; /* nominal date [CCYYDDD] */ /* ** Calculate the Time */ hour = (int) *( header + 11 ); min = (int) *( header + 12 ); sec = (int) *( header + 13 ); time = 10000*hour + 100*min + sec; mcdir[4] = time; /* nominal time [HHMMSS] */ mcdir[5] = 1; /* upper left image line */ mcdir[6] = 1; /* upper left image element */ /* ** Get the number of lines and elements in the image */ mcdir[9] = GetInt( header + 16, 2 ); /* Elements */ mcdir[8] = GetInt( header + 18, 2 ); /* Lines */ /* ** Set some more AREA header values */ mcdir[10] = 1; /* # bytes per data point */ mcdir[11] = (int) *( header + 41 ); /* line resolution */ mcdir[12] = (int) *( header + 41 ); /* element resolution */ mcdir[13] = 1; /* # spectral bands */ mcdir[14] = 0; /* length of line prefix */ mcdir[15] = 0; /* SSEC creation project # */ if ( sss_id < 33 ) { /* Spectral band map */ mcdir[18] = 1 << (sss_id-1); } else { mcdir[18] = 0; mcdir[19] = 1 << (sss_id-32-1); } (void) strncpy( (char *) &mcdir[24], cmemo, 32 ); mcdir[33] = 4 * (IMG_DIR_LEN + NAV_COD_LEN); /* offset to start data */ mcdir[34] = 4 * IMG_DIR_LEN; /* offset to start of nav */ mcdir[45] = ccyyddd - 1900000; /* start date [CCCDDD] */ mcdir[46] = mcdir[4]; /* start time [HHMMSS] */ mcdir[51] = lit_( "VISR", 4 ); /* image source */ mcdir[52] = lit_( "BRIT", 4 ); /* calibration type */ mcdir[62] = 0; /* offset to start of cal */ return SUCCESS; } /******************************* GiniToMcCal *********************************/ int GiniToMcCal( unsigned char *header, int *calcod ) /* ** Name: GiniToMcCal ** ** Purpose: Convert GINI calibration to McIDAS format ** ** Parameters: ** header - GINI format PDB header (521 bytes) ** calcod - McIDAS navigation codicil ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** ** History: 20020418 - Created to handle Unidata calibration blocks ** */ { char unit[9]; /* unit listed in GINI Cal */ int iname; /* name for Cal block */ int iunit; /* unit for Cal block */ int i, j; /* loop index */ int band_id; /* band number */ int creator; /* create entity */ int scale=10000; /* Cal scale value */ int idscal; /* */ int jscale=100000000; /* */ int dbz; /* echo strength [dbZ] */ int dvip[]={-1, 30, 60, 70, 75, 80, 85};/* DVIP break points */ int navcal; /* Nav/Cal indicator */ int noctet; /* # octets in PDB */ int version; /* PDB version for create entity */ int minb; /* min brightness values */ int maxb; /* max brightness values */ int mind; /* min data values */ int maxd; /* max data values */ int temp; /* temporary storage */ #if DEBUG_ENTRY M0sxtrce( "in GiniToMcCal" ); #endif /* ** Extract information from the header (values are 1-based): ** ** octet(s) meaning ** ---------+--------------------------------------------- ** 43 Data compression indicator ** 44 Version number for PDB for entity in octet #2 ** 45-46 Number of octets in the PDB ** 47 Navigation/Calibration indicator: ** 0 -> Nav/Cal info not included (typical) ** 1 -> Nav/Cal info both included ** 2 -> Nav info only included ** 3 -> Cal info only included ** 48-512 Blanks unless Nav or Cal included ** 48-51 unit of calibration (8 characters) ** 52 Number of calibration segments ** 53-56 minimum display brightness ** 57-60 maximum display brightness */ creator = (int) *( header + 1 ); /* <<<<< UPC add 20051007 >>>>> */ band_id = (int) *( header + 3 ); #if DEBUG_MCCAL (void) sprintf( dbg, "GiniToMcCal:: create id: %d, band id: %d", creator, band_id ); M0sxtrce( dbg ); #endif version = header[43]; noctet = GetInt( header + 44, 2 ); navcal = header[46]; #if DEBUG_MCCAL (void) sprintf( dbg, "GiniToMcCal:: version: %d noctet: %d nvcal: %d", version, noctet, navcal ); M0sxtrce( dbg ); #endif if ( navcal == 128 ) { /* Unidata Cal block found; unpack values */ (void) memcpy( unit, (char *)(header+47), 8 ); unit[8] = '\0'; (void) Mcupcase( unit ); calcod[0] = header[55]; #if DEBUG_MCCAL (void) sprintf( dbg, "GiniToMcCal:: Cal unit = %s #image Cal segs = %d", unit, calcod[0] ); M0sxtrce( dbg ); #endif if ( !strncmp( unit, "INCH", 4 ) ) { iname = lit_( "RAIN", 4 ); iunit = lit_( "IN ", 4 ); } else if ( !strncmp( unit, "DBZ", 3 ) ) { iname = lit_( "ECHO", 4 ); iunit = lit_( "DBZ ", 4 ); } else if ( !strncmp( unit, "KFT", 3 ) ) { iname = lit_( "TOPS", 4 ); iunit = lit_( "KFT ", 4 ); } else if ( !strncmp( unit, "KG/M", 4 ) ) { iname = lit_( "VIL ", 4 ); iunit = lit_( "mm ", 4 ); } else { iname = lit_( " ", 4 ); iunit = lit_( " ", 4 ); } if ( calcod[0] > 0 ) { for ( i = 0; i < calcod[0]; i++ ) { minb = GetInt( header + 56 + i*16, 4 ) / 10000; maxb = GetInt( header + 60 + i*16, 4 ) / 10000; mind = GetInt( header + 64 + i*16, 4 ); maxd = GetInt( header + 68 + i*16, 4 ); idscal = 1; while ( !(mind % idscal) && !(maxd % idscal) ) { idscal *= 10; } idscal /= 10; if ( idscal < jscale ) jscale = idscal; #if DEBUG_MCCAL (void) sprintf( dbg, "GiniToMcCal:: minB: %d maxB: %d minD: %d maxD: %d idscal: %d jscale: %d", minb, maxb, mind, maxd, idscal, jscale ); M0sxtrce( dbg ); #endif calcod[1+i*8] = iname; calcod[2+i*8] = mind; calcod[3+i*8] = maxd; calcod[4+i*8] = minb; calcod[5+i*8] = maxb; calcod[6+i*8] = iunit; calcod[7+i*8] = 0; } if ( jscale > scale ) jscale = scale; scale /= jscale; /* <<<<< UPC mod 20101122 - allow fractional dBZs >>>>> */ if ( !strncmp( (char *)&iname, "ECHO", 4 ) ) { if ( scale < 10 ) { jscale /= (10/scale); scale = 10; } } if ( !strncmp( (char *)&iname, "RAIN", 4 ) ) { if ( scale < 100 ) { jscale /= (100/scale); scale = 100; } } for ( i = 0; i < calcod[0]; i++ ) { calcod[2+i*8] /= jscale; calcod[3+i*8] /= jscale; calcod[7+i*8] = scale; #if DEBUG_MCCAL (void) sprintf( dbg, "GiniToMcCal:: minB: %d maxB: %d minD: %d maxD: %d jscale: %d scale: %d", calcod[4+i*8], calcod[5+i*8], calcod[2+i*8], calcod[3+i*8], jscale, scale ); M0sxtrce( dbg ); #endif } } else { return FAILURE; } if ( !strncmp( (char *)&iname, "ECHO", 4 ) ) { /* ** Add Cal block for VIP */ for ( i = 1; i < 7; i++ ) { j = 8 * calcod[0]; calcod[1+j] = lit_( "VIP ", 4 ); calcod[2+j] = i-1; calcod[3+j] = i-1; calcod[4+j] = dvip[i-1]+1; calcod[5+j] = dvip[i]; calcod[6+j] = lit_( "VIP ", 4 ); calcod[7+j] = 1; calcod[8+j] = 0; calcod[0]++; } } #if 0 /* <<<<< 20051010 UPC removed - this was under else block even though the code is clearly cal for Chiz's radar mosaics */ case 26: /* Cal block for NET composite */ #if DEBUG_MCCAL M0sxtrce( "GiniToMcCal:: GINI Echo Tops" ); #endif calcod[ 0] = 1; calcod[ 1] = lit_( "TOPS", 4 ); calcod[ 2] = 0; calcod[ 3] = 80; calcod[ 4] = 0; calcod[ 5] = 255; calcod[ 6] = lit_( "K FT", 4 ); calcod[ 7] = 1; calcod[ 8] = 0; break; case 27: /* Cal block for N0R composite */ case 28: /* Cal block for NCR composite */ #if DEBUG_MCCAL M0sxtrce( "GiniToMcCal:: GINI Reflectivity" ); #endif calcod[ 0] = 1; calcod[ 1] = lit_( "ECHO", 4 ); calcod[ 2] = 0; calcod[ 3] = 105; calcod[ 4] = 0; calcod[ 5] = 255; calcod[ 6] = lit_( "dBZ ", 4 ); calcod[ 7] = 1; calcod[ 8] = 30; break; case 29: /* AUX block for NVL composite */ #if DEBUG_MCCAL M0sxtrce( "GiniToMcCal:: GINI Vert. Int. Liq. H2O" ); #endif calcod[ 0] = 1; calcod[ 1] = lit_( "H2O ", 4 ); calcod[ 2] = 0; calcod[ 3] = 85; calcod[ 4] = 0; calcod[ 5] = 255; calcod[ 6] = lit_( "mm ", 4 ); calcod[ 7] = 1; calcod[ 8] = 0; break; case 30: /* AUX block for N1P composite */ #if DEBUG_MCCAL M0sxtrce( "GiniToMcCal:: GINI 1-hour Precip." ); #endif calcod[ 0] = 1; calcod[ 1] = lit_( "RAIN", 4 ); calcod[ 2] = 0; calcod[ 3] = 120; calcod[ 4] = 0; calcod[ 5] = 255; calcod[ 6] = lit_( "IN ", 4 ); calcod[ 7] = 10; calcod[ 8] = 0; break; case 31: /* AUX block for NTP composite */ #if DEBUG_MCCAL M0sxtrce( "GiniToMcCal:: GINI Story Total Precip." ); #endif calcod[ 0] = 1; calcod[ 1] = lit_( "RAIN", 4 ); calcod[ 2] = 0; calcod[ 3] = 240; calcod[ 4] = 0; calcod[ 5] = 255; calcod[ 6] = lit_( "IN ", 4 ); calcod[ 7] = 10; calcod[ 8] = 0; break; #endif } else { switch ( band_id ) { /* CAL block/AUX block depend on band */ case 0: /* No CAL/AUX block for VIS */ #if DEBUG_MCCAL M0sxtrce( "GiniToMcCal:: GINI VIS band" ); #endif calcod[ 0] = 0; break; case 2: /* CAL block for IR bands */ case 3: case 4: case 5: case 6: /* <<<<< UPC add 20051007 >>>>> */ case 7: /* <<<<< UPC add 20051007 >>>>> */ if ( band_id != 3 ) { /* 3.9, 10.7, 12.0 um IR */ #if DEBUG_MCCAL M0sxtrce( "GiniToMcCal:: GINI IR band" ); #endif calcod[ 0] = 2; calcod[ 1] = lit_( "TEMP", 4 ); calcod[ 2] = 2420; calcod[ 3] = 1630; calcod[ 4] = 176; calcod[ 5] = 255; calcod[ 6] = lit_( "K ", 4 ); calcod[ 7] = 10; calcod[ 8] = 0; calcod[ 9] = lit_( "TEMP", 4 ); calcod[10] = 3300; calcod[11] = 2420; calcod[12] = 0; calcod[13] = 176; calcod[14] = lit_( "K ", 4); calcod[15] = 10; calcod[16] = 0; } else { /* 6.8 um IR (WV) */ #if DEBUG_MCCAL M0sxtrce( "GiniToMcCal:: GINI WV band" ); #endif calcod[ 0] = 1; calcod[ 1] = lit_( "TEMP", 4 ); calcod[ 2] = 2630; calcod[ 3] = 2130; calcod[ 4] = 0; calcod[ 5] = 255; calcod[ 6] = lit_( "K ", 4 ); calcod[ 7] = 10; calcod[ 8] = 0; } break; default: return FAILURE; } } /* ** Regularize values in Cal block: ** ** calcod[ 0] == number of cal segments ** calcod[ 1] == name of 1st cal segment ** calcod[ 2] == minD <-> minB in 1st cal segment ** calcod[ 3] == maxD <-> maxB in 1st cal segment ** calcod[ 4] == minB in 1st cal segment ** calcod[ 5] == maxB in 1st cal segment ** calcod[ 6] == unit represented in 1st cal segment ** calcod[ 7] == scale factor for minD/maxD in 1st cal segment ** calcod[ 8] == offset for minD/maxD in 1st cal segment ** ** calcld[ 9] == name of 2st cal segment ** calcod[10] == minD <-> minB in 2nd cal seg 2 ** ... */ for ( i = 0; i < calcod[0]; i++ ) { if ( calcod[4+(i*8)] > calcod[5+(i*8)] ) { temp = calcod[2+(i*8)]; calcod[2+(i*8)] = calcod[3+(i*8)]; calcod[3+(i*8)] = temp; temp = calcod[4+(i*8)]; calcod[4+(i*8)] = calcod[5+(i*8)]; calcod[5+(i*8)] = temp; } } /* ** GINI imagery don't have a RAW -> BRIT calibration block; add one. */ maxb = -9999; for ( i = 0; i < calcod[0]; i++ ) { if ( calcod[4+(i*8)] > maxb ) maxb = calcod[4+(i*8)]; if ( calcod[5+(i*8)] > maxb ) maxb = calcod[5+(i*8)]; } i = 8 * calcod[0]; calcod[1+i] = lit_( "BRIT", 4 ); calcod[2+i] = 0; /* NB: this may look incorrect, */ calcod[3+i] = 255; /* but it isn't */ calcod[4+i] = 0; calcod[5+i] = maxb; calcod[6+i] = lit_( "BRIT", 4 ); calcod[7+i] = 1; calcod[8+i] = 0; calcod[0]++; /* ** Done */ #if DEBUG_MCCAL i = 0; (void) sprintf( dbg, "GiniToMcCal:: calcod[%2d] = %6d %4X", i, calcod[i], calcod[i] ); M0sxtrce( dbg ); for ( i = 1; i <= 8*calcod[0]; i++ ) { if ( ischar_( &calcod[i] ) ) { (void) memcpy( unit, (char *)&calcod[i], 4 ); unit[4] = 0; (void) sprintf( dbg, "GiniToMcCal:: calcod[%2d] = %6s %04x", i, unit, calcod[i] ); } else { (void) sprintf( dbg, "GiniToMcCal:: calcod[%2d] = %6d %04x", i, calcod[i], calcod[i] ); } M0sxtrce( dbg ); } #endif return SUCCESS; } /****************************** GetGiniHeader ********************************/ int GetGiniHeader( FILELIST *cur, unsigned char *header ) /* ** Name: GetGiniHeader ** ** Purpose: Read the GINI image header. This skips the Product ** Identification Block (PIB) which usually comes first. ** ** Parameters: ** cur - FILELIST structure containing current image information ** name - full qualified name of the file ** pos - position to add to list ** hoff - byte offset to beginning of image header ** doff - byte offset to beginning of image data ** size - number of lines in Zlib compressed block ** type - file type ** time - file data time [sec since 1970] ** header - returned image header ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** ** History: 20000321 - Create by GINI to AREA file converter ** */ { char buf[GINI_ZBUF_LEN]; /* working buffer */ char head[GINI_HED_LEN+1]; /* working buffer */ char *b; /* generic pointer */ char *p; /* generic pointer */ int rc; /* function return code */ int zlibed=0; /* indicates zlib compression */ FILE *fd; /* file descriptor */ #if DEBUG_ENTRY M0sxtrce( "in GetGiniHeader" ); #endif /* ** Initialize */ cur->hoff = 0; /* ** Read beginning of the file to see whether or not the PIB is present. ** ** Bytes Meaning ** -----------+------------------------------------ ** 0 - n Product Identification Block ** n+1 - n+512 Product Definition Block ** ** File types: ** ** type Origin ** ---- ---------------------------------------------- ** 0 NOAAPORT uncompressed; UPC uncompressed ** 1 NOAAPORT Zlib compressed ** 2 Unidata PNG compressed (uncompressible with pngg2gini) */ fd = fopen ( cur->name, "rb" ); if ( fd == (FILE *) NULL ) { return FAILURE; } rc = fread ( buf, (size_t) 1, sizeof(buf), fd ); (void) fclose( fd ); if ( rc != (int) sizeof(buf) ) { #if DEBUG_HEADR (void) sprintf( dbg,"GetGiniHeader:: GINI read wanted: %d got: %d", sizeof(buf), rc); M0sxtrce( dbg ); #endif return FAILURE; } /* ** "For all NESDIS interface products the CCCC (originating station ** identifier) that follows the T1T2A1A2ii will be 'KNES' indicating ** that the product originated from the NESDIS interface in Camp ** Springs, Maryland." ** ** For NEXRAD Level III composites created by the UPC, CCCC is set to ** 'CHIZ'. ** ** If 'KNES'/'CHIZ' is included in the header, then the Product ** Identification Block has a non-zero length. If it does not appear, ** then the PIB is assumed to not be present. */ buf[sizeof(buf)-1] = 0; /* NULL terminate */ p = strstr( buf, "KNES" ); if ( p == (char *) NULL ) p = strstr( buf, "CHIZ" ); if ( p != (char *) NULL ) { /* 'KNES' or 'CHIZ' found */ p = strstr( p, "\r\r\n" ); /* <<<<< UPC mod 20030710 >>>>> */ if ( p != (char *) NULL ) { /* CR CR NL not found */ p += 3; cur->hoff = p - buf; } } else { p = buf; } cur->doff = cur->hoff + GINI_PDB_LEN; /* beginning of data */ if ( IsZlibHed( p ) ) { /* <<<<< UPC add 20030710 >>>>> */ z_stream d_stream; /* Zlib decompression stream */ cur->type = 1; /* Zlib compressed - type 1 */ M0sxtrce( "GetGiniHeader:: Zlib-compressed GINI block found" ); d_stream.zalloc = (alloc_func) 0; d_stream.zfree = (free_func) 0; d_stream.opaque = (voidpf) 0; d_stream.next_in = (Bytef *) p; d_stream.avail_in = (uInt) (sizeof(buf)-1-cur->hoff); d_stream.next_out = head; d_stream.avail_out = (uInt) sizeof(head); if ( inflateInit( &d_stream ) != Z_OK ) { M0sxtrce( "GetGiniHeader:: Zlib inflateInit error" ); return FAILURE; } rc = inflate( &d_stream, Z_NO_FLUSH ); if ( rc != Z_OK && rc != Z_STREAM_END ) { M0sxtrce( "GetGiniHeader:: Zlib inflate error" ); return FAILURE; } if ( d_stream.total_out != GINI_HED_LEN ) { M0sxtrce( "GetGiniHeader:: Zlib inflated image header size error" ); return FAILURE; } if ( inflateEnd( &d_stream ) != Z_OK ) { M0sxtrce( "GetGiniHeader:: Zlib inflateEnd error" ); return FAILURE; } head[sizeof(head)-1] = '\0'; p = strstr( head, "KNES" ); if ( p == (char *) NULL ) p = strstr( head, "CHIZ" ); if ( p != (char *) NULL ) { /* 'KNES' or 'CHIZ' found */ p = strstr( p, "\r\r\n" ); if ( p != (char *) NULL ) { /* CR CR NL not found */ p += 3; } } else { p = head; } cur->doff = cur->hoff + d_stream.total_in; /* beginning of data */ #if UNIDATA } else if ( ispnghed_((unsigned char *)p+GINI_PDB_LEN) ) {/* <<<<< UPC add 20070121 >>>>> */ cur->type = 2; /* PNG compressed - type 2 */ M0sxtrce( "GetGiniHeader:: PNG-compressed GINI block found" ); #endif } else { cur->type = 0; /* Uncompressed - type 0 */ M0sxtrce( "GetGiniHeader:: uncompressed GINI block found" ); } (void) memmove( header, p, GINI_PDB_LEN ); #if DEBUG_HEADR (void) sprintf( dbg, "GetGiniHeader:: cur->hoff: %d", cur->hoff ); M0sxtrce( dbg ); #endif return SUCCESS; } /******************************** IsZlibHed **********************************/ int IsZlibHed( unsigned char *buf ) /* ** Name: IsZlibHed ** ** Purpose: Check a two-byte sequence to see if it indicates the start of ** a zlib-compressed buffer ** ** Parameters: ** buf - buffer containing at least two bytes ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** */ { #if DEBUG M0sxtrce( "in IsZlibHed" ); #endif unsigned char b0 = *buf; unsigned char b1 = *(buf+1); /* ** These tests were extracted from the 'inflate.c' routine that is ** distributed with the zlib distribution. */ if ( (b0 & 0xf) == Z_DEFLATED ) { if ( (b0 >> 4) + 8 <= DEF_WBITS ) { if ( !(((b0 << 8) + b1) % 31) ) { return SUCCESS; } } } return FAILURE; }
Attachment:
giniadir.cp
Description: Binary data
Attachment:
giniaget.cp
Description: Binary data
/**** $Id: servutil.c,v 1.11 2010/08/30 17:35:42 tomy Tst $ ****/ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> /* * This is part of a rotten hack to get around a GNUC compiler bug on * IRIX when passing small structures to functions (check the call to * "inet_ntoa" later in the source code for more information). */ #if defined(__sgi__) && defined(__GNUC__) && \ ((_MIPS_SIM == _ABIN32) || (_MIPS_SIM == _ABI64)) extern in_addr_t inet_addr(const char *); extern char * inet_ntoa(); #else #include <arpa/inet.h> #endif #include <dirent.h> #include <stdio.h> #include <stdlib.h> #include <strings.h> #include <time.h> #include <sys/stat.h> #include <glob.h> #include <regex.h> #include "mcidas.h" #include "mcidasp.h" #include "servutil.h" /* <<<<< UPC add 20081202 - add needed function prototypes >>>>> */ Fint lit_( const char *, FsLen ); int LineRes = 0; int ElemRes = 0; static char dbg[MAX_ERR_LEN]; /* debug message */ /******************************** GetFileList ********************************/ int GetFileList( CRITERIA *request, FILELIST **list ) /* ** Name: GetFileList ** ** Purpose: Search directory 'dir' for files matching 'mask' ** ** Parameters: ** dir - directory to search ** request - criteria file has to match to be acceptable ** list - list of files matching 'mask' ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** */ { int i; /* generic counter */ int len; /* length of string variable */ int rc; /* status return flag */ int indxl=-1; /* replacable location in string */ int indxu=-1; /* replacable location in string */ char *filename; /* file mask used for glob */ char id[MAX_ID_LEN]; /* station ID */ char ptype[MAX_ID_LEN]; /* dataset descriptor */ char *p; /* generic character pointer */ /* <<<<< UPC add 20051005 - Add date holders >>>>> */ char date[9]; /* CCYYMMDD [UTC] */ char jdate[8]; /* CCYYJJJ [UTC] */ char hour[3]; /* HH */ char minute[3]; /* MM */ char second[3]; /* SS */ char hhmmss[7]; /* HHMMSS */ char ctime[9]; /* HH:MM:SS */ time_t now; /* current time */ glob_t fmatches; /* array of glob file matches */ FILELIST cur={0}; /* FILELIST struct of image info */ struct stat file_stat; /* 'stat' information */ #if DEBUG M0sxtrce( "in GetFileList" ); #endif /* ** Set request file mask if it is blank. */ if ( !request->filemask ) { (void) strcpy( request->filemask, "*" ); } /* ** If a LIST of station IDs is requested, let GetIDList handle it. */ if ( !strncmp( request->id, "LIST", 4 ) ) { return GetIDList( request, list ); } /* ** Create the space for the file name mask */ len = strlen(request->dirmask) + strlen(request->filemask) + 2; len += MAX_TOK_LEN * NumToken(request->dirmask); len += MAX_TOK_LEN * NumToken(request->filemask); filename = malloc( len ); if ( filename == (char *) NULL ) { M0sxtrce( "GetFileList:: error mallocing filename" ); return FAILURE; } p = request->dirmask + strlen(request->dirmask) - 1; (void) strcpy( filename, request->dirmask ); if ( *p != '/' ) { (void) strcat( filename, "/" ); } (void) strcat( filename, request->filemask ); /* ** Get current time in UTC */ now = time((time_t *)0); { struct tm *timeptr = gmtime(&now); struct tm tmptimeptr; /* * Copy "*timeptr" to "tmptimeptr" as a workaround for * possible bugs in "strftime" (e.g. Solaris 2.3). */ tmptimeptr = *timeptr; strftime( date, sizeof date, "%Y%m%d", &tmptimeptr ); strftime( jdate, sizeof jdate, "%Y%j", &tmptimeptr ); strftime( hour, sizeof hour, "%H", &tmptimeptr ); strftime( minute, sizeof minute, "%M", &tmptimeptr ); strftime( second, sizeof second, "%S", &tmptimeptr ); strftime( hhmmss, sizeof hhmmss, "%H%M%S", &tmptimeptr ); strftime( ctime, sizeof ctime, "%T", &tmptimeptr ); } /* ** Substitute replacables in fully qualified filename. */ (void) strcpy( id, request->id ); (void) Mclocase( id ); (void) strcpy( ptype, request->ptype ); (void) Mclocase( ptype ); indxu = ReplaceToken( filename, "\\TYPE", request->ptype ); indxl = ReplaceToken( filename, "\\type", ptype ); indxu = ReplaceToken( filename, "\\PROD", request->ptype ); indxl = ReplaceToken( filename, "\\prod", ptype ); indxu = ReplaceToken( filename, "\\ID", request->id ); indxl = ReplaceToken( filename, "\\id", id ); indxu = ReplaceToken( filename, "\\CURDAY", date ); indxl = ReplaceToken( filename, "\\curday", date ); (void) sprintf( dbg, "GetFileList:: file directory matching mask: %s", filename ); M0sxtrce( dbg ); /* ** Generate a list of all files matching the filename mask */ rc = glob( filename, NULL, NULL, &fmatches ); if ( rc == GLOB_NOSPACE || #if defined(__FreeBSD__) || defined(__APPLE__) rc == GLOB_NOCHECK || rc == GLOB_ABEND ) #else rc == GLOB_NOMATCH || rc == GLOB_ABORTED ) #endif { (void) sprintf( dbg, "GetFileList:: no files found matching: %s", filename ); M0sxtrce( dbg ); free( filename ); return FAILURE; } (void) sprintf( dbg, "GetFileList:: matching pattern list length: %d", fmatches.gl_pathc ); M0sxtrce( dbg ); /* ** Select all matches EXCEPT directories */ for ( i = 0; i < fmatches.gl_pathc; i++ ) { (void) stat( fmatches.gl_pathv[i], &file_stat ); if ( !S_ISDIR( file_stat.st_mode ) ) { /* Object not a directory */ (void) strcpy( cur.name, fmatches.gl_pathv[i] ); cur.doff = MISS; /* byte offset to image data */ cur.size = file_stat.st_size; /* file size in bytes */ cur.time = MISS; /* file data time */ cur.pos++; rc = PushFileByName( &cur, list ); if ( rc == FAILURE ) { M0sxtrce( "GetFileList:: error adding to file linked list" ); return FAILURE; } (void) sprintf( dbg, "GetFileList:: Position %x %x %x %d filename: %s", list, *list, &list, cur.pos, cur.name ); M0sxtrce( dbg ); } } free( filename ); globfree( &fmatches ); return SUCCESS; } /********************************* GetIDList *********************************/ int GetIDList( CRITERIA *request, FILELIST **list ) /* ** Name: GetIDList ** ** Purpose: Get a list of files by station ID ** ** Parameters: ** request - criteria file has to match to be acceptable ** list - list of files matching 'mask' ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** */ { int i, j; /* counters */ int idloc=0; /* flag for where ID is found */ int idislist; /* flag for request->id as LIST */ int len, lennew; /* length of string variable */ int pos; /* dataset position */ int rc; /* status return flag */ int indxl=-1; /* replacable location in string */ int indxu=-1; /* replacable location in string */ char *dirmask; /* character pointers */ char *filename; /* file mask used for glob */ char *filemask; /* file mask used for regexec */ char *idmask; /* ID mask string */ char *idold; /* concat. list of station IDs */ char *idnew; /* concat. list of station IDs */ char *idtmp; /* working string */ char *p; /* generic character pointer */ /* <<<<< UPC add 20051005 - Add date holders >>>>> */ char date[9]; /* CCYYMMDD [UTC] */ char jdate[8]; /* CCYYJJJ [UTC] */ char hour[3]; /* HH */ char minute[3]; /* MM */ char second[3]; /* SS */ char hhmmss[7]; /* HHMMSS */ char ctime[9]; /* HH:MM:SS */ time_t now; /* current time */ char id[MAX_ID_LEN]; /* station ID */ char reqid[MAX_ID_LEN]; /* requested station ID */ char ptype[MAX_ID_LEN]; /* dataset descriptor */ glob_t dmatches; /* array of glob dir matches */ glob_t fmatches; /* array of glob file matches */ regex_t dirreg; /* compiled reg expr: dirmask */ regex_t filereg; /* compiled reg expr: filemask */ regex_t idreg; /* compiled reg expr: idmask */ size_t nmatch=2; /* number of matches possible */ regmatch_t pmatch[2]; /* struct with match locations */ FILELIST cur={0}; /* FILELIST struct of image info */ FILELIST last={0}; /* FILELIST struct of image info */ FILELIST *temp=NULL; /* list of files in directory */ struct stat file_stat; /* 'stat' information */ #if DEBUG M0sxtrce( "in GetIDList" ); #endif /* ** Create a working buffer */ len = strlen(request->dirmask) + strlen(request->filemask) + 2; len += MAX_TOK_LEN * NumToken(request->dirmask); len += MAX_TOK_LEN * NumToken(request->filemask); filename = malloc( len ); if ( filename == (char *) NULL ) { M0sxtrce( "GetIDList:: error mallocing space for filename" ); return FAILURE; } filemask = malloc( len ); if ( filemask == (char *) NULL ) { M0sxtrce( "GetIDList:: error mallocing space for filemask" ); return FAILURE; } /* ** Save information that request->id == LIST */ if ( strcmp( request->id, "LIST" ) ) { (void) strcpy( reqid, request->id ); idislist = 0; } else { (void) strcpy( reqid, "*" ); idislist = 1; } /* ** Create the full file pathname string */ p = request->dirmask + strlen(request->dirmask) - 1; (void) strcpy( filename, request->dirmask ); if ( *p != '/' ) { (void) strcat( filename, "/" ); } (void) strcat( filename, request->filemask ); (void) strcpy( filemask, filename ); /* ** Find out if \ID or \id is specified as a token */ if ( (strstr(request->dirmask, "\\ID") != (char *) NULL) || (strstr(request->dirmask, "\\id") != (char *) NULL) ) { idloc = 1; } else { if ( (strstr(request->filemask, "\\ID") != (char *) NULL) || (strstr(request->filemask, "\\id") != (char *) NULL) ) { idloc = 2; } } /* ** Get current time in UTC */ now = time((time_t *)0); { struct tm *timeptr = gmtime(&now); struct tm tmptimeptr; /* * Copy "*timeptr" to "tmptimeptr" as a workaround for * possible bugs in "strftime" (e.g. Solaris 2.3). */ tmptimeptr = *timeptr; strftime( date, sizeof date, "%Y%m%d", &tmptimeptr ); strftime( jdate, sizeof jdate, "%Y%j", &tmptimeptr ); strftime( hour, sizeof hour, "%H", &tmptimeptr ); strftime( minute, sizeof minute, "%M", &tmptimeptr ); strftime( second, sizeof second, "%S", &tmptimeptr ); strftime( hhmmss, sizeof hhmmss, "%H%M%S", &tmptimeptr ); strftime( ctime, sizeof ctime, "%T", &tmptimeptr ); } /* ** Substitute replacables in fully qualified filename. */ (void) strcpy( id, reqid ); (void) Mclocase( id ); (void) strcpy( ptype, request->ptype ); (void) Mclocase( ptype ); indxu = ReplaceToken( filename, "\\TYPE", request->ptype ); indxl = ReplaceToken( filename, "\\type", ptype ); indxu = ReplaceToken( filename, "\\PROD", request->ptype ); indxl = ReplaceToken( filename, "\\prod", ptype ); indxu = ReplaceToken( filename, "\\ID", reqid ); indxl = ReplaceToken( filename, "\\id", id ); indxu = ReplaceToken( filename, "\\CURDAY", date ); indxl = ReplaceToken( filename, "\\curday", date ); (void) sprintf( dbg, "GetIDList:: file name matching mask: %s", filename ); M0sxtrce( dbg ); /* ** Now get a list of files, one per station ID. ** ** There are three different approaches in the following: ** ** ID location Approach ** ----------- -------- ** directory 1) get list of directories with an ID in their name ** (fastest) 2) use glob to get a sorted list of files in each ** directory ** 3) choose last file name from the glob list for each ** directory; this will be the entry returned in 'list' ** ** file name 1) generate a name mask that will be used to match ** (slow!) the station ID in the list of files ** 2) use glob to generate a list of files that match ** the file mask ** 3) use the name mask to select one file for each ID ** from the many that may have been generated by glob ** ** none 1) use glob to generate a list of files ** (glacial!) 2) report full list of files (ugh!!) ** */ switch ( idloc ) { case 1: M0sxtrce( "GetIDList:: ID specified in dirmask" ); len = strlen( request->dirmask); len += MAX_TOK_LEN * NumToken( request->dirmask ); dirmask = malloc( len ); if ( dirmask == (char *) NULL ) { M0sxtrce( "GetIDList:: error mallocing dirmask" ); free( filename ); free( filemask ); return FAILURE; } (void) strcpy( dirmask, request->dirmask ); p = dirmask + strlen( dirmask ) - 1; if ( *p == '/' ) *p = 0; indxu = ReplaceToken( dirmask, "\\ID", "[A-Z][A-Z][A-Z]" ); if ( indxu == -1 ) indxl = ReplaceToken( dirmask, "\\id", "[A-Z][A-Z][A-Z]" ); indxu = ReplaceToken( dirmask, "\\TYPE", request->ptype ); if ( indxu == -1 ) indxl = ReplaceToken( dirmask, "\\type", request->ptype ); indxu = ReplaceToken( dirmask, "\\PROD", request->ptype ); if ( indxu == -1 ) indxl = ReplaceToken( dirmask, "\\prod", request->ptype ); indxu = ReplaceToken( dirmask, "\\CURDAY", date ); if ( indxu == -1 ) indxl = ReplaceToken( dirmask, "\\curday", date ); rc = regcomp ( &dirreg, (const char *) dirmask, REG_EXTENDED ); if ( rc != 0 ) { M0sxtrce( "GetIDList:: regcomp failed for dirreg" ); free( dirmask ); free( filename ); free( filemask ); return FAILURE; } rc = glob( dirmask, GLOB_NOSORT, NULL, &dmatches ); if ( rc == GLOB_NOSPACE || #if defined(__FreeBSD__) || defined(__APPLE__) rc == GLOB_NOCHECK || rc == GLOB_ABEND ) #else rc == GLOB_NOMATCH || rc == GLOB_ABORTED ) #endif { (void) sprintf( dbg, "GetIDList:: no files found matching: %s", dirmask ); M0sxtrce( dbg ); free( filename ); free( filemask ); globfree( &dmatches ); return FAILURE; } (void) sprintf( dbg, "GetIDList:: glob for dirmask returns %d", dmatches.gl_pathc ); M0sxtrce( dbg ); for ( i = 0; i < dmatches.gl_pathc; i++ ) { (void) stat( dmatches.gl_pathv[i], &file_stat ); if ( S_ISDIR( file_stat.st_mode ) ) { /* Want only directories */ (void) sprintf( dbg, "GetIDList:: match %2d: %s", i, dmatches.gl_pathv[i] ); M0sxtrce( dbg ); (void) strcpy( filemask, dmatches.gl_pathv[i] ); (void) strcat( filemask, "/" ); (void) strcat( filemask, request->filemask ); indxu = ReplaceToken( filemask, "\\TYPE", request->ptype ); indxl = ReplaceToken( filemask, "\\type", ptype ); indxu = ReplaceToken( filemask, "\\PROD", request->ptype ); indxl = ReplaceToken( filemask, "\\prod", ptype ); indxu = ReplaceToken( filemask, "\\ID", reqid ); indxl = ReplaceToken( filemask, "\\id", id ); (void) sprintf( dbg, "GetIDList:: filemask: %s", filemask ); M0sxtrce( dbg ); rc = glob( filemask, (int) NULL, NULL, &fmatches ); if ( rc == GLOB_NOSPACE || #if defined(__FreeBSD__) || defined(__APPLE__) rc == GLOB_NOCHECK || rc == GLOB_ABEND ) #else rc == GLOB_NOMATCH || rc == GLOB_ABORTED ) #endif { (void) sprintf( dbg, "GetIDList:: no files found matching: %s", dirmask ); M0sxtrce( dbg ); #if 0 free( filename ); free( filemask ); globfree( &fmatches ); return FAILURE; #endif continue; } if ( fmatches.gl_pathc > 0 ) { j = fmatches.gl_pathc - 1; (void) stat( fmatches.gl_pathv[j], &file_stat ); while ( S_ISDIR( file_stat.st_mode ) ) { /* skip directories */ j--; if ( j < 0 ) break; (void) stat( fmatches.gl_pathv[j], &file_stat ); } if ( j >= 0 ) { (void) sprintf( dbg, "GetIDList:: adding to list: %s", fmatches.gl_pathv[j] ); M0sxtrce( dbg ); (void) strcpy( cur.name, fmatches.gl_pathv[j] ); cur.doff = MISS; /* byte offset to image data */ cur.size = file_stat.st_size; /* file size in bytes */ cur.time = MISS; /* file data time */ cur.pos++; rc = PushFileByName( &cur, list ); if ( rc == FAILURE ) { M0sxtrce( "GetIDList:: error saving file list" ); free( filename ); free( filemask ); globfree( &dmatches ); globfree( &fmatches ); return FAILURE; } } } } globfree( &fmatches ); } globfree( &dmatches ); break; case 2: M0sxtrce( "GetIDList:: ID specified in filemask" ); lennew = len; idmask = malloc( lennew ); if ( idmask == (char *) NULL ) { M0sxtrce( "GetIDList:: error mallocing space for idmask" ); free( filename ); free( filemask ); return FAILURE; } idnew = malloc( lennew ); if ( idnew == (char *) NULL ) { M0sxtrce( "GetIDList:: error mallocing space for idnew" ); free( filename ); free( filemask ); free( idmask ); return FAILURE; } idold = malloc( lennew ); if ( idold == (char *) NULL ) { M0sxtrce( "GetIDList:: error mallocing space for idold" ); free( filename ); free( filemask ); free( idmask ); free( idnew ); return FAILURE; } idtmp = malloc( lennew ); if ( idold == (char *) NULL ) { M0sxtrce( "GetIDList:: error mallocing space for idold" ); free( filename ); free( filemask ); free( idmask ); free( idnew ); free( idold ); return FAILURE; } /* ** Substitute replaceables in the masks to be used for regexec. */ indxu = ReplaceToken( filemask, ".", "\\." ); indxu = ReplaceToken( filemask, "*", ".*" ); indxu = ReplaceToken( filemask, "\\TYPE", request->ptype ); indxl = ReplaceToken( filemask, "\\type", ptype ); indxu = ReplaceToken( filemask, "\\PROD", request->ptype ); indxl = ReplaceToken( filemask, "\\prod", ptype ); (void) strcpy( idmask, filemask ); indxu = ReplaceToken( idmask, "\\ID", "( )" ); if ( indxu == -1 ) indxl = ReplaceToken( idmask, "\\id", "( )" ); (void) sprintf( dbg, "GetIDList:: station ID matching mask: %s", filemask ); M0sxtrce( dbg ); indxu = ReplaceToken( filemask, "\\ID", "([A-Z][A-Z][A-Z])" ); if ( indxu == -1 ) indxl = ReplaceToken( filemask, "\\id", "([A-Z][A-Z][A-Z])" ); (void) sprintf( dbg, "GetIDList:: file name matching mask: %s", filemask ); M0sxtrce( dbg ); (void) strcpy( idold, " " ); *idnew = 0; /* ** Compile the regular expression that will be used to get the ** station ID */ rc = regcomp ( &filereg, (const char *) filemask, REG_EXTENDED ); if ( rc != 0 ) { M0sxtrce( "GetIDList:: regcomp failed for filereg" ); free( filename ); free( filemask ); free( idmask ); free( idnew ); free( idold ); return FAILURE; } /* ** Compile the regular expression that will be used to test the ** station ID */ rc = regcomp ( &idreg, (const char *) idmask, REG_EXTENDED ); if ( rc != 0 ) { M0sxtrce( "GetIDList:: regcomp failed for idreg" ); free( filename ); free( filemask ); free( idmask ); free( idnew ); free( idold ); return FAILURE; } /* ** Generate a list of all files matching the filename mask */ rc = glob( filename, GLOB_NOSORT, NULL, &fmatches ); if ( rc == GLOB_NOSPACE || #if defined(__FreeBSD__) || defined(__APPLE__) rc == GLOB_NOCHECK || rc == GLOB_ABEND ) #else rc == GLOB_NOMATCH || rc == GLOB_ABORTED ) #endif { (void) sprintf( dbg, "GetIDList:: no files found matching: %s", filename ); M0sxtrce( dbg ); free( filename ); free( filemask ); free( idmask ); free( idnew ); free( idold ); globfree( &fmatches ); return FAILURE; } /* ** Eliminate any matches that are directories */ (void) sprintf( dbg, "GetIDList:: matching pattern list length: %d", fmatches.gl_pathc ); M0sxtrce( dbg ); for ( i = 0; i < fmatches.gl_pathc; i++ ) { (void) stat( fmatches.gl_pathv[i], &file_stat ); if ( !S_ISDIR( file_stat.st_mode ) ) { /* Want only files */ (void) strcpy( cur.name, fmatches.gl_pathv[i] ); cur.doff = MISS; /* byte offset to image data */ cur.size = file_stat.st_size; /* file size in bytes */ cur.time = MISS; /* file data time */ cur.pos++; (void) sprintf( dbg, "GetIDList:: filename: %s", cur.name ); M0sxtrce( dbg ); rc = PushFileByName( &cur, &temp ); if ( rc == FAILURE ) { M0sxtrce( "GetIDList:: error saving temp file list" ); free( filename ); free( filemask ); free( idmask ); free( idnew ); free( idold ); globfree( &fmatches ); return FAILURE; } } } /* ** If request is for a LIST of IDs AND the \ID replaceable was specified ** then use regexec to generate a list of file names one per NEXRAD ** station. */ /* ** Compare the first file name in the list of potential matches ** to the regular expression in filereg. */ cur = *temp; pos = 1; while ( cur.next != (FILELIST *) NULL ) { if ( regexec( &idreg, cur.name, nmatch, pmatch, 0 ) ) { /* ** Save name on list */ cur.pos = pos++; rc = PushFileByName( &cur, list ); (void) sprintf( dbg, "GetIDList:: name: %s count: %d", cur.name, cur.pos ); M0sxtrce ( dbg ); /* ** Get the station ID from the name */ if ( regexec( &filereg, cur.name, nmatch, pmatch, 0 ) ) { M0sxtrce( "GetIDList:: error matching filemask" ); free( filename ); free( filemask ); free( idmask ); free( idnew ); free( idold ); globfree( &fmatches ); return FAILURE; } /* ** Save previously used ID mask */ if ( cur.pos >= 2 ) { lennew += 4; (void) strcpy( idtmp, idmask ); idmask = realloc( idmask, lennew ); (void) strcpy( idmask, idtmp ); (void) strcpy( idtmp, idnew ); idnew = realloc( idnew, lennew ); (void) strcpy( idnew, idtmp ); idold = realloc( idold, lennew ); idtmp = realloc( idtmp, lennew ); (void) strcpy( idold, idnew ); (void) strcat( idnew, "|" ); } /* ** Update ID mask with newly found station ID */ len = strlen( idnew ); (void) strncpy( idnew+len, pmatch[1].rm_so + cur.name, 3 ); *(idnew + len + 3) = 0; indxu = ReplaceToken( idmask, idold, idnew ); (void) sprintf( dbg, "GetIDList:: idmask: %s", idmask ); M0sxtrce( dbg ); /* ** Compile the ID matching regular expression using new ID list */ if ( regcomp ( &idreg, (const char *) idmask, REG_EXTENDED ) ) { M0sxtrce( "GetIDList:: regcomp failed for idreg" ); free( filename ); free( filemask ); free( idmask ); free( idnew ); free( idold ); globfree( &fmatches ); return FAILURE; } } cur = *cur.next; } free( idmask ); free( idnew ); free( idold ); globfree( &fmatches ); break; default: M0sxtrce( "GetIDList:: ID not specified anywhere" ); rc = glob( filename, GLOB_NOSORT, NULL, &fmatches ); if ( rc == GLOB_NOSPACE || #if defined(__FreeBSD__) || defined(__APPLE__) rc == GLOB_NOCHECK || rc == GLOB_ABEND ) #else rc == GLOB_NOMATCH || rc == GLOB_ABORTED ) #endif { (void) sprintf( dbg, "GetIDList:: no files found matching: %s", filename ); M0sxtrce( dbg ); free( filename ); free( filemask ); globfree( &fmatches ); return FAILURE; } (void) sprintf( dbg, "GetIDList:: glob for filename returns %d", fmatches.gl_pathc ); M0sxtrce( dbg ); for ( i = 0; i < fmatches.gl_pathc; i++ ) { (void) stat( fmatches.gl_pathv[i], &file_stat ); if ( !S_ISDIR( file_stat.st_mode ) ) { /* Want only files */ (void) sprintf( dbg, "GetIDList:: match %2d: %s", i, fmatches.gl_pathv[i] ); M0sxtrce( dbg ); (void) strcpy( cur.name, fmatches.gl_pathv[i] ); cur.doff = MISS; /* byte offset to image data */ cur.size = file_stat.st_size; /* file size in bytes */ cur.time = MISS; /* file data time */ rc = PushFileByName( &cur, list ); if ( rc == FAILURE ) { M0sxtrce( "GetIDList:: error saving file list" ); free( filename ); free( filemask ); globfree( &fmatches ); return FAILURE; } } } globfree( &fmatches ); break; } free( filename ); free( filemask ); return SUCCESS; } /******************************** GetImgCards ********************************/ int GetImgCards( FILELIST *cur, int *aradir, int *navcod, int *auxblk, int *cards, char *err ) /* ** Name: GetImgCards ** ** Purpose: Build the required ADDE comment cards containing the center ** point and res information ** ** Parameters: ** cur - FILELIST structure containing current image information ** name - full qualified name of the file ** pos - position to add to list ** doff - byte offset to beginning of image data ** size - file size in bytes ** ctime - file creation time [sec since 1970] ** time - file data time [sec since 1970] ** aradir - McIDAS area directory for name ** navcod - McIDAS navigation codicil ** auxblk - McIDAS auxiliary block ** cards - McIDAS comment cards returned as integers ** err - error string from ReadImgDir ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** */ { char one_card[MAX_CARD_LEN-1]; /* a single comment card */ float elem; /* center element of image */ float lat; /* center latitude of image */ float line; /* center line of image */ float lon; /* center longitude of image */ float resx; /* elem res (km) at center */ float resy; /* line res (km) at center */ int add; /* UPCAddCard function return */ int num_cards=0; /* number of cards built */ int rc; /* function return status */ /* ** Get center line/element of image */ #if DEBUG M0sxtrce( "in GetImgCards" ); #endif line = (aradir[8] * aradir[11]) / 2.0; elem = (aradir[9] * aradir[12]) / 2.0; #if DEBUG (void) sprintf( dbg, "GetImgCards:: center point: line: %f elem: %f ", line, elem ); M0sxtrce( dbg ); #endif /* ** Get center lat/lon of image */ LineRes = aradir[11]; ElemRes = aradir[12]; rc = NavImgToEarth( cur, navcod, line, elem, &lat, &lon, err ); if ( rc != FAILURE ) { /* ** Build cards for center point */ (void) sprintf( one_card, CEN_LAT_CARD, lat ); num_cards++; add = UPCAddCard( one_card, MAX_CARD_LEN, cards, num_cards ); if ( add == FAILURE ) { (void) strcpy( err, "Unable to allocate memory" ); return FAILURE; } (void) sprintf( one_card, CEN_LON_CARD, lon ); num_cards++; add = UPCAddCard(one_card, MAX_CARD_LEN, cards, num_cards); if ( add == FAILURE ) { (void) strcpy( err, "Unable to allocate memory" ); return FAILURE; } } else { /* center point failure */ return FAILURE; } /* ** Get the resolution at the center point of the image */ rc = GetImgRes( cur, navcod, line, elem, &resx, &resy, err ); if ( rc != FAILURE ) { /* ** Build Latitude/Longitude cards for the resolution */ (void) sprintf( one_card, RES_X_CARD, (int)(resx+0.5) ); num_cards++; add = UPCAddCard( one_card, MAX_CARD_LEN, cards, num_cards ); if ( add == FAILURE ) { (void)strcpy(err, "Unable to allocate memory"); return FAILURE; } (void) sprintf( one_card, RES_Y_CARD, (int)(resy+0.5) ); num_cards++; add = UPCAddCard( one_card, MAX_CARD_LEN, cards, num_cards ); if ( add == FAILURE ) { (void) strcpy( err, "Unable to allocate memory" ); return FAILURE; } /* ** Build Computed Latitude/Longitude cards for the resolution */ (void) sprintf( one_card, CRES_X_CARD, resx ); num_cards++; add = UPCAddCard( one_card, MAX_CARD_LEN, cards, num_cards ); if ( add == FAILURE ) { (void)strcpy(err, "Unable to allocate memory"); return FAILURE; } (void) sprintf( one_card, CRES_Y_CARD, resy ); num_cards++; add = UPCAddCard( one_card, MAX_CARD_LEN, cards, num_cards ); if ( add == FAILURE ) { (void) strcpy( err, "Unable to allocate memory" ); return FAILURE; } } else { /* ** resolution failure */ return FAILURE; } /* ** Get the valid unit type for this image */ rc = GetImgUnits( aradir, auxblk, cards, &num_cards, err ); /* ** Change mcword 64 in the area directory to reflect the number ** of comment cards */ aradir[63] = aradir[63] + num_cards; return SUCCESS; } /********************************* GetImgRes *********************************/ int GetImgRes( FILELIST *cur, int *navcod, float line, float elem, float *resx, float *resy, char *err ) /* ** Name: GetImgRes ** ** Purpose: Calculate image resolution at center point ** ** Parameters: ** cur - FILELIST structure containing current image information ** name - full qualified name of the file ** pos - position to add to list ** size - file size in bytes ** ctime - file creation time [sec since 1970] ** time - file data time [sec since 1970] ** navcod - navigation codicil ** line - input image line ** elem - input image element ** resx - output x-resolution at center of image (km) ** resy - output y-resolution at center of image (km) ** err - error string returned ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** */ { static char lastname[MAX_NAME_LEN]=""; /* filename last time in func. */ double azimuth; /* directional azimuth (unused) */ double range1; /* range from center down */ double range2; /* range from down 1 line to over 1 element */ Freal dum1; /* dummy variable */ Freal dum2; /* dummy variable */ Freal lat; /* lat to measure distance */ Freal lat2; /* lat to measure distance */ Freal lon; /* lon to measure distance */ Freal lon2; /* lon to measure distance */ Freal fline; /* line position for res calc */ Freal felem; /* elem position for res calc */ int i; /* loop counter */ int llflag; /* variable for nv1ini */ int rc; /* function status */ int two=2; /* the number two (2) */ #if DEBUG M0sxtrce( "in GetImgRes" ); #endif if ( strcmp(lastname, cur->name) != 0 ) { llflag = lit_( "LL ", 4 ); rc = nv1ini_( &two, &llflag ); if ( rc != 0 ) { (void) sprintf( err, "GetImgRes:: Error in McIDAS navigation. NV1INI returns %d", rc ); M0sxtrce( err ); return FAILURE; } (void) strcpy( lastname, cur->name ); } fline = line; felem = elem; (void) sprintf( dbg, "GetImgRes:: fline %f felem %f ", fline, felem ); M0sxtrce( dbg ); rc = nv1sae_( &line, &elem, &dum1, &lat, &lon, &dum2 ); if ( rc != 0 ) { (void) strcpy( err, "GetImgRes:: Unable to transform line/element to lat/lon" ); return FAILURE; } /* ** Move down one line and find the lat/lon */ fline = fline + LineRes; rc = nv1sae_( &fline, &felem, &dum1, &lat2, &lon2, &dum2 ); if ( rc != 0 ) { (void) strcpy( err, "GetImgRes:: Unable to transform line/element to lat/lon" ); return FAILURE; } #if DEBUG (void) sprintf( dbg, "GetImgRes:: %f %f lat2 %f lon2 %f rc %d", fline, felem, lat2, lon2, rc ); M0sxtrce( dbg ); #endif /* ** Find range from center to down one line */ rc = lltora_( &lat, &lon, &lat2, &lon2, &range1, &azimuth ); if ( rc != 0 ) { (void) sprintf( err, "GetImgRes:: Error in McIDAS navigation. LLTORA returns %d", rc ); return FAILURE; } /* ** Move over one element and find the lat/lon */ fline = fline - LineRes; felem = felem + ElemRes; rc = nv1sae_( &fline, &felem, &dum1, &lat2, &lon2, &dum2 ); if ( rc != 0 ) { (void) strcpy( err, "GetImgRes:: Unable to transform line/element to lat/lon" ); return FAILURE; } /* ** Find range from center to down one line */ rc = lltora_( &lat, &lon, &lat2, &lon2, &range2, &azimuth ); if ( rc != 0 ) { (void) sprintf( err, "GetImgRes:: Error in McIDAS navigation. LLTORA returns %d", rc ); return FAILURE; } /* ** Image resolution that is not equal in the LINe and ELEment dimensions */ *resy = range1; *resx = range2; (void) sprintf( dbg, "GetImgRes:: resx: %f resy: %f", range2, range1 ); M0sxtrce( dbg ); return SUCCESS; } /******************************* NavEarthToImg *******************************/ int NavEarthToImg( FILELIST *cur, int *navcod, float lat, float lon, float *line, float *elem, char *err ) /* ** Name: NavEarthToImg ** ** Purpose: Convert image lat/lon into line/elem ** ** Parameters: ** cur - FILELIST structure containing current image information ** name - full qualified name of the file ** pos - position to add to list ** size - file size in bytes ** ctime - file creation time [sec since 1970] ** time - file data time [sec since 1970] ** navcod - input latitude ** lat - input latitude ** lon - input longitude ** line - output image line of lat/lon ** elem - output image element of lat/lon ** err - error string returned ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** */ { static char lastname[MAX_NAME_LEN]=""; /* filename last time in func. */ float dum; /* dummy variable */ int rc; /* function status */ int len; /* byte len of navcod */ int llflag; /* variable for nv1ini */ int one=1; /* the number one (1) */ int two=2; /* the number two (2) */ #if DEBUG M0sxtrce( "in NavEarthToImg" ); #endif if ( strcmp( lastname, cur->name ) != 0 ) { /* ** Initialize McIDAS nav transforms */ rc = nvprep_( &one, navcod ); if ( rc != 0 ) { (void) sprintf( err, "Error in McIDAS navigation. NVPREP returns %d", rc ); return FAILURE; } llflag = lit_( "LL ", 4 ); rc = nv1ini_( &two, &llflag ); if (rc != 0) { (void) sprintf( err, "Error in McIDAS navigation. NV1INI returns %d", rc ); return FAILURE; } (void) strcpy( lastname, cur->name ); } rc = nv1eas_( &lat, &lon, &dum, line, elem, &dum ); if ( rc != 0 ) { (void) strcpy( err, "Unable to transform lat/lon to line/element" ); return FAILURE; } return SUCCESS; } /******************************* NavImgToEarth *******************************/ int NavImgToEarth( FILELIST *cur, int *navcod, float line, float elem, float *lat, float *lon, char *err ) /* ** Name: NavImgToEarth ** ** Purpose: Convert image line/elem into lat/lon ** ** Parameters: ** cur - FILELIST structure containing current image information ** name - full qualified name of the file ** pos - position to add to list ** size - file size in bytes ** ctime - file creation time [sec since 1970] ** time - file data time [sec since 1970] ** navcod - McIDAS navigation codicil ** line - input image line ** elem - input image element ** lat - output latitude of line/elem ** lon - output longitude of line/elem ** err - error string returned ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** */ { static char lastname[MAX_NAME_LEN]=""; /* filename last time in func. */ float dum1; /* dummy variable */ float dum2; /* dummy variable */ int rc; /* function status */ int llflag; /* variable for nv1ini */ int one=1; /* the number one (1) */ int two=2; /* the number two (2) */ #if DEBUG M0sxtrce( "in NavImgToEarth" ); #endif if ( strcmp(lastname, cur->name) != 0 ) { /* ** Initialize McIDAS nav transforms */ rc = nvprep_( &one, navcod ); if ( rc != 0 ) { (void) sprintf( err, "Error in McIDAS navigation. NVPREP returns %d", rc ); return FAILURE; } llflag = lit_( "LL ", 4 ); rc = nv1ini_( &two, &llflag ); if ( rc != 0 ) { (void) sprintf( err, "NavImgToEarth:: Error in McIDAS navigation NV1INI returns %d", rc ); M0sxtrce( err ); return FAILURE; } (void) strcpy( lastname, cur->name ); } rc = nv1sae_( &line, &elem, &dum1, lat, lon, &dum2 ); if ( rc != 0 ) { (void) strcpy( err, "NavImgToEarth:: Unable to transform line/element to lat/lon" ); M0sxtrce( err ); return FAILURE; } return SUCCESS; } /********************************* NumToken **********************************/ int NumToken( char *string ) /* ** Name: NumToken ** ** Purpose: Counts number of "replaceable" tokens in string ** ** Parameters: ** string - string to be checked ** Returns: ** ntok -> number of tokens found ** */ { char *p, *e; /* string pointers */ int ntok=0; /* token counter */ p = string; e = p + strlen( string ) - 1; while ( (p <= e) && ((strstr(p,"\\") != (char *) NULL) || (strstr(p,"*") != (char *) NULL) || (strstr(p,"?") != (char *) NULL) ) ) { ntok++; p++; } return ntok; } /********************************* PushFile **********************************/ int PushFile( FILELIST *cur, FILELIST **list ) /* ** Name: PushFile ** ** Purpose: Add a name and pos to a linked list without any sorting ** ** Parameters: ** name - filename to add to list ** pos - position to add to list ** list - list to which to add item ** ** Returns: ** SUCCESS 1 ** FAILURE 0 */ { #if DEBUG M0sxtrce( "in PushFile" ); #endif FILELIST *new=NULL; /* ** malloc a new node */ new = (FILELIST *) malloc( sizeof(FILELIST) ); if ( new == NULL ) { return FAILURE; } /* ** Fill the new struct with values */ *new = *cur; /* ** Insert new element into the list */ if ( (*list) == NULL ) { new->next = NULL; } else { new->next = *list; } *list = new; return SUCCESS; } /******************************* PushFileByName ******************************/ int PushFileByName( FILELIST *cur, FILELIST **list ) /* ** Name: PushFileByName ** ** Purpose: Add an image to a linked list sorted alphebetically by name ** ** Parameters: ** cur - FILELIST structure containing info for current file: ** name - full qualified name of the file ** pos - position to add to list ** size - file size in bytes ** ctime - file creation time [sec since 1970] ** time - file data time [sec since 1970] ** list - list to which to add item ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** */ { int strmatch; /* return from 'strcmp' */ FILELIST *after; /* pointer to list of files */ FILELIST *insert; /* pointer to list of files */ FILELIST *new=NULL; /* pointer to list of files */ #if DEBUG M0sxtrce( "in PushFileByName" ); #endif /* ** malloc a new node */ new = (FILELIST *) malloc( sizeof(FILELIST) ); if ( new == NULL ) { return FAILURE; } /* ** Fill the new struct with values */ *new = *cur; /* ** This is the first element in the list */ if ( (*list) == NULL ) { new->next = NULL; *list = new; return SUCCESS; } /* ** Compare file basenames */ strmatch = strcmp( Mcbasename(new->name), Mcbasename((*list)->name) ); /* ** Insert the new element at the head */ if ( strmatch <= 0 ) { new->next = *list; *list = new; return SUCCESS; } /* ** Insert the new element at the appropriate place in the list */ insert = *list; while (1) { after = insert->next; /* ** end of list? */ if (after == NULL) break; strmatch = strcmp(Mcbasename(new->name), Mcbasename(after->name)); /* ** If the name is greater than the current name, we insert here */ if ( strmatch <= 0 ) break; insert = after; } insert->next = new; new->next = after; return SUCCESS; } /****************************** PushFileByTime *******************************/ int PushFileByTime( FILELIST *cur, FILELIST **list ) /* ** Name: PushFileByTime ** ** Purpose: Add an image to a linked list sorted chronologically ** such that the most recent image at the head of the list ** ** Parameters: ** cur - FILELIST structure containing current file information: ** name - filename to add to list ** pos - position number of name ** size - file size in bytes ** ctime - file creation time [sec since 1970] ** time - file data time [sec since 1970] ** list - list to which to add item ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** */ { FILELIST *after; FILELIST *insert; FILELIST *new=NULL; #if DEBUG M0sxtrce( "in PushFileByTime" ); #endif /* ** malloc a new node */ new = (FILELIST *) malloc( sizeof(FILELIST) ); if ( new == NULL ) return FAILURE; /* ** Fill the new struct with values */ *new = *cur; /* ** This is the first element in the list */ if ( (*list) == NULL ) { new->next = NULL; *list = new; return SUCCESS; } /* ** Insert the new element at the head if its time is newer. */ if ( (*list)->time < cur->time ) { new->next = *list; *list = new; return SUCCESS; } /* ** Insert the new element at the appropriate place in the list */ insert = *list; while (1) { /* ** End of list? */ after = insert->next; if ( after == NULL ) break; /* ** If the time is greater than the current, insert it here */ if ( after->time < cur->time ) break; insert = after; } insert->next = new; new->next = after; return SUCCESS; } /********************************** PopFile **********************************/ int PopFile( FILELIST *cur, FILELIST **list ) /* ** Name: PopFile ** ** Purpose: Remove an image from a linked list ** ** Parameters: ** cur - FILELIST structure containing current file information: ** name - filename to remove from list ** pos - position to remove from list ** size - file size in bytes ** ctime - file creation time [sec since 1970] ** time - file data time [sec since 1970] ** list - list remove which to remove item ** ** Returns: ** SUCCESS 1 ** */ { #if DEBUG M0sxtrce( "in PopFile" ); #endif /* ** Copy an element from 'list' to 'cur' and move to next struct in 'list' */ *cur = *(*list); (*list) = (*list)->next; return SUCCESS; } /****************************** UPCCheckImgBounds *******************************/ int UPCCheckImgBounds( READPARM *read, int nlines, int nelems ) /* ** Name: UPCCheckImgBounds ** ** Purpose: check to see if the image limits requested will encompass any ** data. if not, failure is returned ** ** Parameters: ** read - READPARM struct containing read specs ** nlines - number of lines requested ** nelems - number of elements requested ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** */ { int rc=SUCCESS; /* return code, assume success */ #if DEBUG M0sxtrce( "in UPCCheckImgBounds" ); #endif /* ** Check top */ if ( (read->ul_line / read->line_res) + nlines <= 0 ) { rc = FAILURE; } /* ** Check bottom */ if ( read->ul_line >= read->maxlin ) { rc = FAILURE; } /* ** Check left */ if ( (read->ul_elem / read->elem_res) + nelems <= 0 ) { rc = FAILURE; } /* ** Check right */ if ( read->ul_elem >= read->maxele ) { rc = FAILURE; } return (rc); } /****************************** ReadCodLengths *******************************/ int ReadCodLengths( char *source, int *callen, int *navlen, int *auxlen ) /* ** Name: ReadCodLengths ** ** Purpose: Return cal and nav codicil byte lengths based on input ** source type ** ** Parameters: ** source - McIDAS source type (AAA, GVAR, TIRO, ...) ** callen - byte length of calibration codicil ** navlen - byte length of navigation codicil ** ** Returns: ** SUCCESS 1 ** FAILURE 0 ** */ { #if DEBUG M0sxtrce( "in ReadCodLengths" ); #endif /* ** Sort through known McIDAS source types */ if (strcmp(source, "AAA ") == 0) { *callen = 512; *navlen = 512; *auxlen = 0; } else if (strcmp(source, "GVAR") == 0) { *callen = 512; *navlen = 512 * 5; *auxlen = 0; } else if (strcmp(source, "TIRO") == 0) { *callen = 512; *navlen = 512; *auxlen = 0; } else if (strcmp(source, "NEXR") == 0) { *callen = 0; *navlen = 512; *auxlen = 256; } else if (strcmp(source, "NIDS") == 0) { *callen = 0; *navlen = 512; *auxlen = 256; } else { /* unknown source type, try default values */ *callen = 512; *navlen = 512; *auxlen = 0; return FAILURE; } return SUCCESS; } /******************************* GetConfigInfo *******************************/ int GetConfigInfo( const char *ctype, const char *cfile, CONFIG *cfg, char *err ) /* ** Name: GetConfigInfo ** ** Purpose: Read Unidata ADDE server configuration files and return ** information ** ** Parameters: ** ctype - dataset group name ** cfile - configuration file name ** cfg - CONFIG structure containing: ** dataloc - location of data files ** infoname - name of auxiliary information file ** filemask - mask for data file names ** ipmask - mask of acceptable IP addresses ** err - error return message ** ** Returns: ** SUCCESS 1 ** FAILURE 0 */ { const char *pathname=NULL; /* file path/name mask */ char *p, *q; /* generic character pointers */ int nargs=0; /* #arguments found in info file */ int rc; /* status return flag */ #if DEBUG M0sxtrce( "in GetConfigInfo" ); #endif /* ** If a configuration file was specified, extract information from ** it. Otherwise, get configuration information from MASK= keyword. */ if ( *cfile != 0 ) { /* search configuration file */ const char *value; char *fullname; /* fully qualified pathname */ char line[256]; /* lines from configuration file */ char dmask[256]; /* directory mask keyword */ char fmask[256]; /* file mask keyword */ char imask[256]; /* info file mask keyword */ char pmask[256]; /* IP address mask keyword */ int argh; /* handle for arg fetchers */ int parsed_len; /* byte length of arg block */ FILE *fd=NULL; /* file descriptor */ M0sxtrce( "GetConfigInfo:: INFO= specified" ); fullname = (char *) Mcpathname( cfile ); fd = fopen( fullname, "r" ); if ( fd == (FILE *) NULL ) { (void) sprintf( err, "error opening configuration file" ); return FAILURE; } (void) sprintf( dmask, "%s_DIR", ctype ); (void) sprintf( fmask, "%s_FILE", ctype ); (void) sprintf( imask, "%s_INFO", ctype ); (void) sprintf( pmask, "%s_IP", ctype ); /* ** Read and process lines until EOF */ while ( fgets(line, 256, fd) != (char *) NULL ) { if ( (p = strstr( line, "\n")) != (char *)NULL ) *p = 0; if ( (p = strstr( line, "#" )) != (char *)NULL ) *p = 0; if ( (p = strstr( line, "=" )) != (char *)NULL ) { argh = Mcargparse( (const char *) line, NULL, &parsed_len ); if ( Mcargnum( argh, "DIRMASK") > 0 ) { rc = Mcargstr( argh, "DIR.MASK", 1, "./", &value ); strcpy( cfg->dataloc, value ); nargs++; } else if ( Mcargnum( argh, "FILEMASK" ) > 0 ) { rc = Mcargstr( argh, "FILE.MASK", 1, "*", &value ); strcpy( cfg->filemask, value ); nargs++; } else if ( Mcargnum( argh, "INFOFILE" ) > 0 ) { rc = Mcargstr( argh, "INFO.FILE", 1, "NOWRAD.DIR", &value ); strcpy( cfg->infoname, value ); nargs++; } else if ( Mcargnum( argh, "IPMASK" ) > 0 ) { rc = Mcargstr( argh, "IP.MASK", 1, "*", &value ); strcpy( cfg->ipmask, value ); nargs++; } else if ( Mcargnum( argh, dmask ) > 0 ) { rc = Mcargstr( argh, dmask, 1, "./", &value ); (void) strcpy( cfg->dataloc, value ); nargs++; } else if ( Mcargnum( argh, fmask ) > 0 ) { rc = Mcargstr( argh, fmask, 1, "*", &value ); (void) strcpy( cfg->filemask, value ); nargs++; } else if ( Mcargnum( argh, imask ) > 0 ) { rc = Mcargstr( argh, imask, 1, "NOWRAD.DIR", &value ); (void) strcpy( cfg->infoname, value ); nargs++; } else if ( Mcargnum( argh, pmask ) > 0 ) { rc = Mcargstr( argh, pmask, 1, "*", &value ); (void) strcpy( cfg->ipmask, value ); nargs++; } rc = Mcargfree( argh ); } } fclose( fd ); } else { /* information in MASK= keyword */ M0sxtrce( "GetConfigInfo:: MASK= specified" ); rc = Mcargstr( 0, "MASK", 1, " ", &pathname ); if ( rc > 0 ) { (void) sprintf( dbg, "GetConfigInfo:: pathname: %s", (char *) pathname ); M0sxtrce( dbg ); p = (char *) pathname; while ( (q=strstr(p, "/")) != (char *) NULL ) { p = q+1; } (void) strcpy( cfg->filemask, p ); *p = 0; (void) strcpy( cfg->dataloc, pathname ); (void) strcpy( cfg->ipmask, "*" ); nargs = 3; } } /* ** Return status based on how many arguments were found in infor file */ if ( nargs >= 1 ) return SUCCESS; else return FAILURE; } /***************************** GetUnitsAndScale ******************************/ int GetUnitsAndScale( char *ctype, char *units, int *scale ) /* ** Name: GetUnitsAndScale ** ** Purpose: Define unit names and scales for NEXRAD Level III products ** and WSI NOWrad (tm) imagery ** ** Parameters: ** ctype - input cal type (RAW, BRIT, ...) ** units - output physical units (" " K, ALB, %, ...) ** scale - output physical scale (1, 10, 100, ...) ** ** NOTE: this function always succeeds ** ** Returns: ** SUCCESS 1 ** FAILURE 0 **/ { #if DEBUG M0sxtrce( "in GetUnitsAndScale" ); #endif /* ** Check the ctype against known values */ if ( strncmp(ctype, "ALB ", 4) == 0 ) { (void) strncpy( units, " % ", 4 ); *scale = 10; } else if ( strncmp(ctype, "RAD ", 4) == 0 ) { (void) strncpy( units, "MW**", 4 ); *scale = 1000; if ( strncmp(ctype, "MSAT", 4) == 0 ) (void) strncpy( units, "WP**", 4 ); } else if ( strncmp(ctype, "TEMP", 4) == 0 ) { (void) strncpy( units, " K ", 4 ); *scale = 10; } else if ( strncmp(ctype, "ECHO", 4) == 0 ) { (void) strncpy( units, "dbZ ", 4 ); *scale = 10; /* <<<<< UPC mod 20100521 - floating point ECHO >>>>> */ } else if ( strncmp(ctype, "TOPS", 4) == 0 ) { (void) strncpy( units, "K FT", 4 ); *scale = 1; } else if ( strncmp(ctype, "RAIN", 4) == 0 ) { (void) strncpy( units, "IN ", 4 ); *scale = 100; } else if ( strncmp(ctype, "H2O", 3) == 0 ) { /* <<<< UPC mod 20030216 >>>>> */ (void) strncpy( units, "MM ", 4 ); *scale = 100; /* <<<<< UPC mod 20100825 - floating point H2O >>>>> */ } else if ( strncmp(ctype, "VEL", 3) == 0 ) { (void) strncpy( units, "KT ", 4 ); *scale = 1; } else if ( strncmp(ctype, "SRMV", 4) == 0 ) { (void) strncpy( units, "KT ", 4 ); *scale = 1; } else if ( strncmp(ctype, "DBA", 3) == 0 ) { M0sxtrce( "GetUnitsAndScale:: matched DBA" ); (void) strncpy( units, "DBA ", 4 ); *scale = 10; } else if ( strncmp(ctype, "DZD", 3) == 0 ) { M0sxtrce( "GetUnitsAndScale:: matched DZD" ); (void) strncpy( units, "DB ", 4 ); *scale = 10; } else if ( strncmp(ctype, "DCC", 3) == 0 ) { M0sxtrce( "GetUnitsAndScale:: matched DCC" ); (void) strncpy( units, "CCOF", 4 ); *scale = 100; } else if ( strncmp(ctype, "DKD", 3) == 0 ) { M0sxtrce( "GetUnitsAndScale:: matched DKD" ); (void) strncpy( units, "DGKM", 4 ); *scale = 10; } else if ( strncmp(ctype, "HC", 2) == 0 ) { M0sxtrce( "GetUnitsAndScale:: matched HC" ); (void) strncpy( units, "CLAS", 4 ); *scale = 1; } else if ( strncmp(ctype, "HHC", 3) == 0 ) { M0sxtrce( "GetUnitsAndScale:: matched HHC" ); (void) strncpy( units, "CLAS", 4 ); *scale = 1; } else if ( strncmp(ctype, "DPR", 3) == 0 ) { M0sxtrce( "GetUnitsAndScale:: matched DPR" ); (void) strncpy( units, "INHR", 4 ); *scale = 1; } else if ( strncmp(ctype, "DAA", 3) == 0 ) { M0sxtrce( "GetUnitsAndScale:: matched DAA" ); (void) strncpy( units, "IN ", 4 ); *scale = 100; } else if ( strncmp(ctype, "DSA", 3) == 0 ) { M0sxtrce( "GetUnitsAndScale:: matched DSA" ); (void) strncpy( units, "IN ", 4 ); *scale = 10; } else { /* default no unit and scale=1 */ M0sxtrce( "GetUnitsAndScale:: did not match any ctype" ); (void) strncpy( units, " ", 4 ); *scale = 1; } return SUCCESS; } /********************************** UPCAddCard *******************************/ int UPCAddCard( char *one_card, int byte_len, int *cards, int num_cards ) /* ** Name: UPCAddCard ** ** Purpose: Add a character string comment card to a buffer of integers ** ** Parameters: ** one_card - text string comment card ** byte_len - max byte length of text string comment card ** cards - integer array of comment cards consisting of text ** num_cards - number of card in the intger array ** ** Returns: ** SUCCESS 1 ** */ { int i; /* loop variable */ int len; /* byte length on one_card */ int off; /* offset into cards array */ #if DEBUG M0sxtrce( "in UPCAddCard" ); #endif /* ** Copy the comment card to the proper position in the integer array */ off = (byte_len) * (num_cards-1); len = strlen(one_card); /* ** Blank out the card trailer and zero the integer array */ for( i = len; i <= byte_len-1; i++ ) one_card[i] = ' '; for( i = off; i <= off+byte_len-1; i++ ) cards[i] = 0; movb_( &byte_len, (void *)one_card, (void *)cards, &off ); return SUCCESS; } /********************************** UPCSendDir *******************************/ int UPCSendDir( int *aradir ) /* ** Name: UPCSendDir ** ** Purpose: Send a McIDAS AREA directory from server to client ** ** Parameters: ** aradir - McIDAS area directory to send ** ** Returns: ** SUCCESS 1 ** */ { int dirbytes; /* number of bytes to send */ #if DEBUG M0sxtrce( "in UPCSendDir" ); #endif /* ** initialize byte lengths to send */ dirbytes = IMG_DIR_LEN * 4; /* ** Swap bytes in synthesized AREA directory */ M0swbyt4( &aradir[0], 20 ); if (ischar_(&aradir[20]) == 0) M0swbyt4( &aradir[20], 1 ); M0swbyt4( &aradir[21], 3 ); M0swbyt4( &aradir[32], 19 ); M0swbyt4( &aradir[53], 1 ); M0swbyt4( &aradir[58], 6 ); /* ** Send the directory to the client */ m0sxsend_( &dirbytes, aradir ); sprintf(dbg, "UPCSendDir:: sent %d bytes of dir", dirbytes); M0sxtrce(dbg); /* ** Swap bytes back in directory */ M0swbyt4( &aradir[0], 20 ); if (ischar_(&aradir[20]) == 0) M0swbyt4( &aradir[20], 1 ); M0swbyt4( &aradir[21], 3 ); M0swbyt4( &aradir[32], 19 ); M0swbyt4( &aradir[53], 1 ); M0swbyt4( &aradir[58], 6 ); return SUCCESS; } /********************************* UPCSendCards ******************************/ int UPCSendCards( int *aradir, int *cards ) /* ** Name: UPCSendCards ** ** Purpose: Send McIDAS comment cards from server to client ** ** Parameters: ** aradir - McIDAS area directory ** cards - McIDAS comment cards to send ** ** Returns: ** SUCCESS 1 ** */ { int cardbytes; /* number of card bytes to send */ #if DEBUG M0sxtrce( "in UPCSendCards" ); #endif cardbytes = aradir[63] * MAX_CARD_LEN; m0sxsend_( &cardbytes, cards ); return SUCCESS; } /********************************** UPCSendAux *******************************/ int UPCSendAux( int *auxblk, int len_aux ) /* ** Name: UPCSendAux ** ** Purpose: Send a McIDAS supplemental block from server to client ** ** Parameters: ** auxblk - McIDAS codicil ** len_aux - length of codicil ** ** Returns: ** SUCCESS 1 ** */ { int i; /* loop variable */ #if DEBUG M0sxtrce( "in UPCSendAux" ); #endif /* ** Send the entire AUX block */ m0sxsend_( &len_aux, auxblk ); return SUCCESS; } /********************************** UPCSendCod *******************************/ int UPCSendCod( int *cod, int len_cod ) /* ** Name: UPCSendCod ** ** Purpose: Send a McIDAS codicil (nav or cal) from server to client ** ** Parameters: ** cod - McIDAS codicil ** len_cod - length of codicil ** ** Returns: ** SUCCESS 1 ** */ { int i; /* loop variable */ #if DEBUG M0sxtrce( "in UPCSendCod" ); #endif /* ** Swap bytes in words without characters */ for ( i = 0; i < len_cod/4; i++ ) if ( ischar_( &cod[i] ) == 0 ) M0swbyt4( &cod[i], 1 ); /* ** Send the entire codicil */ m0sxsend_( &len_cod, cod ); /* ** Swap bytes in words without characters back */ for ( i = 0; i < len_cod/4; i++ ) if ( ischar_( &cod[i] ) == 0 ) M0swbyt4( &cod[i], 1 ); return SUCCESS; } /********************************* UPCSendLine *******************************/ int UPCSendLine( char *buf, int len_buf ) /* ** Name: UPCSendLine ** ** Purpose: Send a line of image data from server to client ** ** Parameters: ** buf - data to send ** len_buf - length of data to send ** bpp - bytes per pixel in buf ** ** Returns: ** SUCCESS 1 ** */ { #if DEBUG M0sxtrce( "in UPCSendLine" ); #endif m0sxsend_( &len_buf, (int *)buf ); return SUCCESS; } /********************************* UPCSendZeros ******************************/ int UPCSendZeros( char *buf, int len_buf ) /* ** Name: UPCSendZeros ** ** Purpose: Send a stream of zeros from server to client ** ** Parameters: ** buf - buffer to fill with zeros ** len_buf - byte number of zeros to send ** ** SUCCESS 1 ** */ { #if DEBUG M0sxtrce( "in UPCSendZeros" ); #endif (void) memset( (void *) buf, 0, len_buf ); (void) UPCSendLine( buf, len_buf ); return SUCCESS; } /******************************* ReplaceToken ********************************/ int ReplaceToken( char *mask, char *token, char *replace ) /* ** Name: ReplaceToken ** ** Purpose: Substitute string for replacable tokens in a string ** ** Parameters: ** mask - string in which to replace token ** token - token to replace ** replace - replacement for token ** ** Note: Valid tokens begin with the '\' character. ** ** Return: >=0 first location of replacable in string ** -1 FAILURE ** ** History: 19990520 - Created for McIDAS-X 7.50 ** 19991201 - Changed logic for replacement ** */ { char *m, *p; /* generic character pointers */ char *string; /* working string */ int loc=-1; /* replacable location in string */ int rlen; /* replacement string length */ int tlen; /* token length */ #if DEBUG M0sxtrce( "in ReplaceToken" ); #endif string = malloc( strlen(mask) ); if ( string == (char *)NULL ) { M0sxtrce( "ReplaceToken:: string token memory allocation error" ); return loc; } m = mask; rlen = strlen( replace ); tlen = strlen( token ); while ( (p = strstr(m,token)) != (char *)NULL ) { if ( loc == -1 ) loc = p - mask; (void) strcpy( string, p+tlen ); *p = 0; (void) strcat( mask, replace ); (void) strcat( mask, string ); (void) sprintf( dbg, "ReplaceToken:: mask: %s", mask ); M0sxtrce( dbg ); m = p + rlen; } (void) free( string ); return loc; } /******************************* AllowedAccess *******************************/ int AllowedAccess( CONFIG cfg, servacct *record ) /* ** Name: AllowedAccess ** ** Purpose: Check to see if client requesting access to a data set ** has been allowed to do so. ** ** Parameters: ** cfg - structure containing directory, file, and IP mask ** for data set access ** record - token to replace ** ** Note: Valid tokens begin with the '\' character. ** ** Return: 1 = SUCCESS ** 0 = FAILURE ** ** History: 19990907 - Created for McIDAS-X 7.60 ** */ { char *ipaddr; /* string IP address of client */ char *ipmask; /* string matching regular expr. */ int rc; /* status return flag */ regex_t idreg; /* compiled reg expr: ipmask */ size_t nmatch=4; /* number of matches possible */ regmatch_t pmatch[4]; /* struct with match locations */ struct in_addr addr_int; /* for inet_ntoa routine */ struct sockaddr_in name; /* will receive the peer name */ int namelen=sizeof(name);/* string length */ #if DEBUG M0sxtrce( "in AllowedAccess" ); #endif /* ** Check to see if the request is from the local machine. If ** so, then there is no need to get its IP address or check ** the configuration file IPMASK to see if it is allowed. */ if ( record->server_address == m0lbaddrn_() ) { (void) sprintf( dbg, "AllowedAccess:: client is local machine" ); M0sxtrce( dbg ); return SUCCESS; } /* ** Check to see if the IPMASK is a global allow (i.e. a '*'). ** If so, then allow access. */ if ( strcmp( cfg.ipmask, "*" ) == 0 ) { (void) sprintf( dbg, "AllowedAccess:: IP mask does not restrict access" ); M0sxtrce( dbg ); return SUCCESS; } /* ** The request is from a different machine. Get its IP address. */ (void) getpeername( 0, (struct sockaddr *) &name, &namelen ); record->client_address = name.sin_addr.s_addr; addr_int.s_addr = name.sin_addr.s_addr; /* ** Turn the file name matching regular expression into a string ** matching regular expression */ ipmask = malloc( 2 * strlen( cfg.ipmask ) ); if ( ipmask == (char *) NULL ) { (void) sprintf( dbg, "AllowedAccess:: error allocating IP mask memory" ); M0sxtrce( dbg ); return FAILURE; } (void) strcpy( ipmask, cfg.ipmask ); rc = ReplaceToken( ipmask, ".", "\\." ); rc = ReplaceToken( ipmask, "*", ".*" ); (void) sprintf( dbg, "AllowedAccess:: string matching IP mask: %s", ipmask ); M0sxtrce( dbg ); /* ** Turn the decimal IP address of the client into a string of ** the "dotted" form (XXX.XXX.XXX.XXX) */ #if defined(__sgi__) && defined(__GNUC__) && \ ((_MIPS_SIM == _ABIN32) || (_MIPS_SIM == _ABI64)) ipaddr = inet_ntoa( *(uint64_t *) &addr_int ); #else ipaddr = inet_ntoa( addr_int ); #endif if ( !ipaddr ) { (void) sprintf( dbg, "AllowedAccess:: inet_ntoa failed for IP address" ); M0sxtrce( dbg ); return FAILURE; } /* ** Compile the regular expression that will be used in the IP ** comparison and then do the comparison. */ rc = regcomp( &idreg, (const char *) ipmask, REG_EXTENDED ); free( ipmask ); if ( rc != 0 ) { (void) sprintf( dbg, "AllowedAccess:: regcomp failed for idreg" ); M0sxtrce( dbg ); return FAILURE; } if ( regexec( &idreg, ipaddr, nmatch, pmatch, 0 ) ) { (void) sprintf( dbg, "AllowedAccess:: client %s denied data set access", ipaddr ); M0sxtrce( dbg ); regfree( &idreg ); return FAILURE; } /* ** Access is allowed. */ (void) sprintf( dbg, "AllowedAccess:: client %s is allowed data set access", ipaddr ); M0sxtrce( dbg ); regfree( &idreg ); return SUCCESS; }