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; }
NOTE: All email exchanges with Unidata User Support are recorded in the Unidata inquiry tracking system and then made publicly available through the web. If you do not want to have your interactions made available in this way, you must let us know in each email you send to us.