This archive contains answers to questions sent to Unidata support through mid-2025. Note that the archive is no longer being updated. We provide the archive for reference; many of the answers presented here remain technically correct, even if somewhat outdated. For the most up-to-date information on the use of NSF Unidata software and data services, please consult the Software Documentation first.
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;
}