LCOV - code coverage report
Current view: directory - frmts/grib/degrib18/degrib - metaparse.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1079 291 27.0 %
Date: 2010-01-09 Functions: 20 14 70.0 %

       1                 : /*****************************************************************************
       2                 :  * metaparse.c
       3                 :  *
       4                 :  * DESCRIPTION
       5                 :  *    This file contains the code necessary to initialize the meta data
       6                 :  * structure, and parse the meta data that comes out of the GRIB2 decoder.
       7                 :  *
       8                 :  * HISTORY
       9                 :  *    9/2002 Arthur Taylor (MDL / RSIS): Created.
      10                 :  *
      11                 :  * NOTES
      12                 :  * 1) Need to add support for GS3_ORTHOGRAPHIC = 90,
      13                 :  *    GS3_EQUATOR_EQUIDIST = 110, GS3_AZIMUTH_RANGE = 120
      14                 :  * 2) Need to add support for GS4_RADAR = 20
      15                 :  *****************************************************************************
      16                 :  */
      17                 : #include <stdio.h>
      18                 : #include <stdlib.h>
      19                 : #include <string.h>
      20                 : #include <math.h>
      21                 : #include "clock.h"
      22                 : #include "meta.h"
      23                 : #include "metaname.h"
      24                 : #include "myassert.h"
      25                 : #include "myerror.h"
      26                 : #include "scan.h"
      27                 : #include "weather.h"
      28                 : #include "memendian.h"
      29                 : #include "myutil.h"
      30                 : 
      31                 : /*****************************************************************************
      32                 :  * MetaInit() --
      33                 :  *
      34                 :  * Arthur Taylor / MDL
      35                 :  *
      36                 :  * PURPOSE
      37                 :  *   To initialize a grib_metaData structure.
      38                 :  *
      39                 :  * ARGUMENTS
      40                 :  * meta = The structure to fill. (Output)
      41                 :  *
      42                 :  * FILES/DATABASES: None
      43                 :  *
      44                 :  * RETURNS: void
      45                 :  *
      46                 :  * HISTORY
      47                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
      48                 :  *
      49                 :  * NOTES
      50                 :  *****************************************************************************
      51                 :  */
      52               6 : void MetaInit (grib_MetaData *meta)
      53                 : {
      54               6 :    meta->element = NULL;
      55               6 :    meta->comment = NULL;
      56               6 :    meta->unitName = NULL;
      57               6 :    meta->convert = 0;
      58               6 :    meta->shortFstLevel = NULL;
      59               6 :    meta->longFstLevel = NULL;
      60               6 :    meta->pds2.sect2.ptrType = GS2_NONE;
      61                 : 
      62               6 :    meta->pds2.sect2.wx.data = NULL;
      63               6 :    meta->pds2.sect2.wx.dataLen = 0;
      64               6 :    meta->pds2.sect2.wx.maxLen = 0;
      65               6 :    meta->pds2.sect2.wx.ugly = NULL;
      66               6 :    meta->pds2.sect2.unknown.data = NULL;
      67               6 :    meta->pds2.sect2.unknown.dataLen = 0;
      68                 : 
      69               6 :    meta->pds2.sect4.numInterval = 0;
      70               6 :    meta->pds2.sect4.Interval = NULL;
      71               6 :    meta->pds2.sect4.numBands = 0;
      72               6 :    meta->pds2.sect4.bands = NULL;
      73                 :    return;
      74                 : }
      75                 : 
      76                 : /*****************************************************************************
      77                 :  * MetaSect2Free() --
      78                 :  *
      79                 :  * Arthur Taylor / MDL
      80                 :  *
      81                 :  * PURPOSE
      82                 :  *   To free the section 2 data in the grib_metaData structure.
      83                 :  *
      84                 :  * ARGUMENTS
      85                 :  * meta = The structure to free. (Input/Output)
      86                 :  *
      87                 :  * FILES/DATABASES: None
      88                 :  *
      89                 :  * RETURNS: void
      90                 :  *
      91                 :  * HISTORY
      92                 :  *   2/2003 Arthur Taylor (MDL/RSIS): Created.
      93                 :  *   3/2003 AAT: Cleaned up declaration of variable: WxType.
      94                 :  *
      95                 :  * NOTES
      96                 :  *****************************************************************************
      97                 :  */
      98               6 : void MetaSect2Free (grib_MetaData *meta)
      99                 : {
     100                 :    size_t i;            /* Counter for use when freeing Wx data. */
     101                 : 
     102               6 :    for (i = 0; i < meta->pds2.sect2.wx.dataLen; i++) {
     103               0 :       free (meta->pds2.sect2.wx.data[i]);
     104               0 :       FreeUglyString (&(meta->pds2.sect2.wx.ugly[i]));
     105                 :    }
     106               6 :    free (meta->pds2.sect2.wx.ugly);
     107               6 :    meta->pds2.sect2.wx.ugly = NULL;
     108               6 :    free (meta->pds2.sect2.wx.data);
     109               6 :    meta->pds2.sect2.wx.data = NULL;
     110               6 :    meta->pds2.sect2.wx.dataLen = 0;
     111               6 :    meta->pds2.sect2.wx.maxLen = 0;
     112               6 :    meta->pds2.sect2.ptrType = GS2_NONE;
     113                 : 
     114               6 :    free (meta->pds2.sect2.wx.data);
     115               6 :    meta->pds2.sect2.unknown.data = NULL;
     116               6 :    meta->pds2.sect2.unknown.dataLen = 0;
     117               6 : }
     118                 : 
     119                 : /*****************************************************************************
     120                 :  * MetaFree() --
     121                 :  *
     122                 :  * Arthur Taylor / MDL
     123                 :  *
     124                 :  * PURPOSE
     125                 :  *   To free a grib_metaData structure.
     126                 :  *
     127                 :  * ARGUMENTS
     128                 :  * meta = The structure to free. (Output)
     129                 :  *
     130                 :  * FILES/DATABASES: None
     131                 :  *
     132                 :  * RETURNS: void
     133                 :  *
     134                 :  * HISTORY
     135                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
     136                 :  *
     137                 :  * NOTES
     138                 :  *****************************************************************************
     139                 :  */
     140               6 : void MetaFree (grib_MetaData *meta)
     141                 : {
     142               6 :    free (meta->pds2.sect4.bands);
     143               6 :    meta->pds2.sect4.bands = NULL;
     144               6 :    meta->pds2.sect4.numBands = 0;
     145               6 :    free (meta->pds2.sect4.Interval);
     146               6 :    meta->pds2.sect4.Interval = NULL;
     147               6 :    meta->pds2.sect4.numInterval = 0;
     148               6 :    MetaSect2Free (meta);
     149               6 :    free (meta->unitName);
     150               6 :    meta->unitName = NULL;
     151               6 :    meta->convert = 0;
     152               6 :    free (meta->comment);
     153               6 :    meta->comment = NULL;
     154               6 :    free (meta->element);
     155               6 :    meta->element = NULL;
     156               6 :    free (meta->shortFstLevel);
     157               6 :    meta->shortFstLevel = NULL;
     158               6 :    free (meta->longFstLevel);
     159               6 :    meta->longFstLevel = NULL;
     160               6 : }
     161                 : 
     162                 : /*****************************************************************************
     163                 :  * ParseTime() --
     164                 :  *
     165                 :  * Arthur Taylor / MDL
     166                 :  *
     167                 :  * PURPOSE
     168                 :  *    To parse the time data from the grib2 integer array to a time_t in
     169                 :  * UTC seconds from the epoch.
     170                 :  *
     171                 :  * ARGUMENTS
     172                 :  * AnsTime = The time_t value to fill with the resulting time. (Output)
     173                 :  *    year = The year to parse. (Input)
     174                 :  *     mon = The month to parse. (Input)
     175                 :  *     day = The day to parse. (Input)
     176                 :  *    hour = The hour to parse. (Input)
     177                 :  *     min = The minute to parse. (Input)
     178                 :  *     sec = The second to parse. (Input)
     179                 :  *
     180                 :  * FILES/DATABASES: None
     181                 :  *
     182                 :  * RETURNS: int (could use errSprintf())
     183                 :  *  0 = OK
     184                 :  * -1 = gribLen is too small.
     185                 :  *
     186                 :  * HISTORY
     187                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
     188                 :  *   4/2003 AAT: Modified to use year/mon/day/hour/min/sec instead of an
     189                 :  *               integer array.
     190                 :  *   2/2004 AAT: Added error checks (because of corrupt GRIB1 files)
     191                 :  *
     192                 :  * NOTES
     193                 :  * 1) Couldn't use the default time_zone variable (concern over portability
     194                 :  *    issues), so we print the hours, and compare them to the hours we had
     195                 :  *    intended.  Then subtract the difference from the AnsTime.
     196                 :  * 2) Need error check for times outside of 1902..2037.
     197                 :  *****************************************************************************
     198                 :  */
     199              24 : int ParseTime (double *AnsTime, int year, uChar mon, uChar day, uChar hour,
     200                 :                uChar min, uChar sec)
     201                 : {
     202                 :    /* struct tm time; *//* A temporary variable to put the time info into. */
     203                 :    /* char buffer[10]; *//* Used when printing the AnsTime's Hr. */
     204                 :    /* int timeZone; *//* The adjustment in Hr needed to get the right UTC * time. */
     205                 : 
     206              24 :    if ((year < 1900) || (year > 2100)) {
     207               0 :       errSprintf ("ParseTime:: year %d is invalid\n", year);
     208               0 :       return -1;
     209                 :    }
     210                 :    /* sec is allowed to be 61 for leap seconds. */
     211              24 :    if ((mon > 12) || (day == 0) || (day > 31) || (hour > 24) || (min > 60) ||
     212                 :        (sec > 61)) {
     213                 :       errSprintf ("ParseTime:: Problems with %d/%d %d:%d:%d\n", mon, day,
     214               0 :                   hour, min, sec);
     215               0 :       return -1;
     216                 :    }
     217              24 :    Clock_ScanDate (AnsTime, year, mon, day);
     218              24 :    *AnsTime += hour * 3600. + min * 60. + sec;
     219                 : /*   *AnsTime -= Clock_GetTimeZone() * 3600;*/
     220                 : 
     221                 : /*
     222                 :    memset (&time, 0, sizeof (struct tm));
     223                 :    time.tm_year = year - 1900;
     224                 :    time.tm_mon = mon - 1;
     225                 :    time.tm_mday = day;
     226                 :    time.tm_hour = hour;
     227                 :    time.tm_min = min;
     228                 :    time.tm_sec = sec;
     229                 :    printf ("%ld\n", mktime (&time));
     230                 :    *AnsTime = mktime (&time) - (Clock_GetTimeZone () * 3600);
     231                 : */
     232                 :    /* Cheap method of getting global time_zone variable. */
     233                 : /*
     234                 :    strftime (buffer, 10, "%H", gmtime (AnsTime));
     235                 :    timeZone = atoi (buffer) - hour;
     236                 :    if (timeZone < 0) {
     237                 :       timeZone += 24;
     238                 :    }
     239                 :    *AnsTime = *AnsTime - (timeZone * 3600);
     240                 : */
     241              24 :    return 0;
     242                 : }
     243                 : 
     244                 : /*****************************************************************************
     245                 :  * ParseSect0() --
     246                 :  *
     247                 :  * Arthur Taylor / MDL
     248                 :  *
     249                 :  * PURPOSE
     250                 :  *   To verify and parse section 0 data.
     251                 :  *
     252                 :  * ARGUMENTS
     253                 :  *      is0 = The unpacked section 0 array. (Input)
     254                 :  *      ns0 = The size of section 0. (Input)
     255                 :  * grib_len = The length of the entire grib message. (Input)
     256                 :  *     meta = The structure to fill. (Output)
     257                 :  *
     258                 :  * FILES/DATABASES: None
     259                 :  *
     260                 :  * RETURNS: int (could use errSprintf())
     261                 :  *  0 = OK
     262                 :  * -1 = ns0 is too small.
     263                 :  * -2 = unexpected values in is0.
     264                 :  *
     265                 :  * HISTORY
     266                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
     267                 :  *
     268                 :  * NOTES
     269                 :  * 1) 1196575042L == ASCII representation of "GRIB"
     270                 :  *****************************************************************************
     271                 :  */
     272               2 : static int ParseSect0 (sInt4 *is0, sInt4 ns0, sInt4 grib_len,
     273                 :                        grib_MetaData *meta)
     274                 : {
     275               2 :    if (ns0 < 9) {
     276               0 :       return -1;
     277                 :    }
     278               2 :    if ((is0[0] != 1196575042L) || (is0[7] != 2) || (is0[8] != grib_len)) {
     279                 :       errSprintf ("ERROR IS0 has unexpected values: %ld %ld %ld\n",
     280               0 :                   is0[0], is0[7], is0[8]);
     281               0 :       errSprintf ("Should be %ld %d %ld\n", 1196575042L, 2, grib_len);
     282               0 :       return -2;
     283                 :    }
     284               2 :    meta->pds2.prodType = (uChar) is0[6];
     285               2 :    return 0;
     286                 : }
     287                 : 
     288                 : /*****************************************************************************
     289                 :  * ParseSect1() --
     290                 :  *
     291                 :  * Arthur Taylor / MDL
     292                 :  *
     293                 :  * PURPOSE
     294                 :  *   To verify and parse section 1 data.
     295                 :  *
     296                 :  * ARGUMENTS
     297                 :  *  is1 = The unpacked section 1 array. (Input)
     298                 :  *  ns1 = The size of section 1. (Input)
     299                 :  * meta = The structure to fill. (Output)
     300                 :  *
     301                 :  * FILES/DATABASES: None
     302                 :  *
     303                 :  * RETURNS: int (could use errSprintf())
     304                 :  *  0 = OK
     305                 :  * -1 = ns1 is too small.
     306                 :  * -2 = unexpected values in is1.
     307                 :  *
     308                 :  * HISTORY
     309                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
     310                 :  *
     311                 :  * NOTES
     312                 :  *****************************************************************************
     313                 :  */
     314               2 : static int ParseSect1 (sInt4 *is1, sInt4 ns1, grib_MetaData *meta)
     315                 : {
     316               2 :    if (ns1 < 21) {
     317               0 :       return -1;
     318                 :    }
     319               2 :    if (is1[4] != 1) {
     320               0 :       errSprintf ("ERROR IS1 not labeled correctly. %ld\n", is1[4]);
     321               0 :       return -2;
     322                 :    }
     323               2 :    meta->center = (unsigned short int) is1[5];
     324               2 :    meta->subcenter = (unsigned short int) is1[7];
     325               2 :    meta->pds2.mstrVersion = (uChar) is1[9];
     326               2 :    meta->pds2.lclVersion = (uChar) is1[10];
     327               2 :    if (((meta->pds2.mstrVersion < 1) || (meta->pds2.mstrVersion > 3)) ||
     328                 :        (meta->pds2.lclVersion > 1)) {
     329               0 :       if (meta->pds2.mstrVersion == 0) {
     330                 :          printf ("Warning: Master table version == 0, was experimental\n"
     331                 :                  "I don't have a copy, and don't know where to get one\n"
     332               0 :                  "Use meta data at your own risk.\n");
     333                 :       } else {
     334                 :          errSprintf ("Master table version supported (1,2,3) yours is %d... "
     335                 :                      "Local table version supported (0,1) yours is %d...\n",
     336               0 :                      meta->pds2.mstrVersion, meta->pds2.lclVersion);
     337               0 :          return -2;
     338                 :       }
     339                 :    }
     340               2 :    meta->pds2.sigTime = (uChar) is1[11];
     341               4 :    if (ParseTime (&(meta->pds2.refTime), is1[12], is1[14], is1[15], is1[16],
     342               4 :                   is1[17], is1[18]) != 0) {
     343               0 :       preErrSprintf ("Error in call to ParseTime from ParseSect1 (GRIB2)");
     344               0 :       return -2;
     345                 :    }
     346               2 :    meta->pds2.operStatus = (uChar) is1[19];
     347               2 :    meta->pds2.dataType = (uChar) is1[20];
     348               2 :    return 0;
     349                 : }
     350                 : 
     351                 : /*****************************************************************************
     352                 :  * ParseSect2_Wx() --
     353                 :  *
     354                 :  * Arthur Taylor / MDL
     355                 :  *
     356                 :  * PURPOSE
     357                 :  *    To verify and parse section 2 data when we know the variable is of type
     358                 :  * Wx (Weather).
     359                 :  *
     360                 :  * ARGUMENTS
     361                 :  *    rdat = The float data in section 2. (Input)
     362                 :  *   nrdat = Length of rdat. (Input)
     363                 :  *    idat = The integer data in section 2. (Input)
     364                 :  *   nidat = Length of idat. (Input)
     365                 :  *      Wx = The weather structure to fill. (Output)
     366                 :  * simpVer = The version of the simple weather code to use when parsing the
     367                 :  *           WxString. (Input)
     368                 :  *
     369                 :  * FILES/DATABASES: None
     370                 :  *
     371                 :  * RETURNS: int (could use errSprintf())
     372                 :  *  0 = OK
     373                 :  * -1 = nrdat or nidat is too small.
     374                 :  * -2 = unexpected values in rdat.
     375                 :  *
     376                 :  * HISTORY
     377                 :  *   2/2003 Arthur Taylor (MDL/RSIS): Created.
     378                 :  *   5/2003 AAT: Stopped messing around with the way buffer and data[i]
     379                 :  *          were allocated.  It was confusing the free routine.
     380                 :  *   5/2003 AAT: Added maxLen to Wx structure.
     381                 :  *   6/2003 AAT: Revisited after Matt (matt@wunderground.com) informed me of
     382                 :  *          memory problems.
     383                 :  *          1) I had a memory leak caused by a buffer+= buffLen
     384                 :  *          2) buffLen could have increased out of bounds of buffer.
     385                 :  *   8/2003 AAT: Found an invalid "assertion" when dealing with non-NULL
     386                 :  *          terminated weather groups.
     387                 :  *
     388                 :  * NOTES
     389                 :  * 1) May want to rewrite so that we don't need 'meta->sect2NumGroups'
     390                 :  *****************************************************************************
     391                 :  */
     392               0 : static int ParseSect2_Wx (float *rdat, sInt4 nrdat, sInt4 *idat,
     393                 :                           uInt4 nidat, sect2_WxType *Wx, int simpVer)
     394                 : {
     395                 :    size_t loc;          /* Where we currently are in idat. */
     396                 :    size_t groupLen;     /* Length of current group in idat. */
     397                 :    size_t j;            /* Counter over the length of the current group. */
     398                 :    char *buffer;        /* Used to store the current "ugly" string. */
     399                 :    int buffLen;         /* Length of current "ugly" string. */
     400                 :    int len;             /* length of current english phrases during creation
     401                 :                          * of the maxEng[] data. */
     402                 :    int i;               /* assists in traversing the maxEng[] array. */
     403                 : 
     404               0 :    if (nrdat < 1) {
     405               0 :       return -1;
     406                 :    }
     407                 : 
     408               0 :    if (rdat[0] != 0) {
     409                 :       errSprintf ("ERROR: Expected rdat to be empty when dealing with "
     410               0 :                   "section 2 Weather data\n");
     411               0 :       return -2;
     412                 :    }
     413               0 :    Wx->dataLen = 0;
     414               0 :    Wx->data = NULL;
     415               0 :    Wx->maxLen = 0;
     416               0 :    for (i = 0; i < NUM_UGLY_WORD; i++) {
     417               0 :       Wx->maxEng[i] = 0;
     418                 :    }
     419                 : 
     420               0 :    loc = 0;
     421               0 :    if (nidat <= loc) {
     422               0 :       errSprintf ("ERROR: Ran out of idat data\n");
     423               0 :       return -1;
     424                 :    }
     425               0 :    groupLen = idat[loc++];
     426                 : 
     427               0 :    loc++;               /* Skip the decimal scale factor data. */
     428                 :    /* Note: This also assures that buffLen stays <= nidat. */
     429               0 :    if (loc + groupLen >= nidat) {
     430               0 :       errSprintf ("ERROR: Ran out of idat data\n");
     431               0 :       return -1;
     432                 :    }
     433                 : 
     434               0 :    buffLen = 0;
     435               0 :    buffer = (char *) malloc ((nidat + 1) * sizeof (char));
     436               0 :    while (groupLen > 0) {
     437               0 :       for (j = 0; j < groupLen; j++) {
     438               0 :          buffer[buffLen] = (char) idat[loc];
     439               0 :          buffLen++;
     440               0 :          loc++;
     441               0 :          if (buffer[buffLen - 1] == '\0') {
     442               0 :             Wx->dataLen++;
     443                 :             Wx->data = (char **) realloc ((void *) Wx->data,
     444               0 :                                           Wx->dataLen * sizeof (char *));
     445                 :             /* This is done after the realloc, just to make sure we have
     446                 :              * enough memory allocated.  */
     447                 :             /* Assert: buffLen is 1 more than strlen(buffer). */
     448               0 :             Wx->data[Wx->dataLen - 1] = (char *)
     449               0 :                   malloc (buffLen * sizeof (char));
     450               0 :             strcpy (Wx->data[Wx->dataLen - 1], buffer);
     451               0 :             if (Wx->maxLen < buffLen) {
     452               0 :                Wx->maxLen = buffLen;
     453                 :             }
     454               0 :             buffLen = 0;
     455                 :          }
     456                 :       }
     457               0 :       if (loc >= nidat) {
     458               0 :          groupLen = 0;
     459                 :       } else {
     460               0 :          groupLen = idat[loc];
     461               0 :          loc++;
     462               0 :          if (groupLen != 0) {
     463               0 :             loc++;      /* Skip the decimal scale factor data. */
     464                 :             /* Note: This also assures that buffLen stays <= nidat. */
     465               0 :             if (loc + groupLen >= nidat) {
     466               0 :                errSprintf ("ERROR: Ran out of idat data\n");
     467               0 :                free (buffer);
     468               0 :                return -1;
     469                 :             }
     470                 :          }
     471                 :       }
     472                 :    }
     473               0 :    if (buffLen != 0) {
     474               0 :       buffer[buffLen] = '\0';
     475               0 :       Wx->dataLen++;
     476                 :       Wx->data = (char **) realloc ((void *) Wx->data,
     477               0 :                                     Wx->dataLen * sizeof (char *));
     478                 :       /* Assert: buffLen is 1 more than strlen(buffer). -- FALSE -- */
     479               0 :       buffLen = strlen (buffer) + 1;
     480                 : 
     481               0 :       Wx->data[Wx->dataLen - 1] = (char *) malloc (buffLen * sizeof (char));
     482               0 :       if (Wx->maxLen < buffLen) {
     483               0 :          Wx->maxLen = buffLen;
     484                 :       }
     485               0 :       strcpy (Wx->data[Wx->dataLen - 1], buffer);
     486                 :    }
     487               0 :    free (buffer);
     488                 :    Wx->ugly = (UglyStringType *) malloc (Wx->dataLen *
     489               0 :                                          sizeof (UglyStringType));
     490               0 :    for (j = 0; j < Wx->dataLen; j++) {
     491               0 :       ParseUglyString (&(Wx->ugly[j]), Wx->data[j], simpVer);
     492                 :    }
     493                 :    /* We want to know how many bytes we need for each english phrase column,
     494                 :     * so we walk through each column calculating that value. */
     495               0 :    for (i = 0; i < NUM_UGLY_WORD; i++) {
     496                 :       /* Assert: Already initialized Wx->maxEng[i]. */
     497               0 :       for (j = 0; j < Wx->dataLen; j++) {
     498               0 :          if (Wx->ugly[j].english[i] != NULL) {
     499               0 :             len = strlen (Wx->ugly[j].english[i]);
     500               0 :             if (len > Wx->maxEng[i]) {
     501               0 :                Wx->maxEng[i] = len;
     502                 :             }
     503                 :          }
     504                 :       }
     505                 :    }
     506               0 :    return 0;
     507                 : }
     508                 : 
     509                 : /*****************************************************************************
     510                 :  * ParseSect2_Unknown() --
     511                 :  *
     512                 :  * Arthur Taylor / MDL
     513                 :  *
     514                 :  * PURPOSE
     515                 :  *    To verify and parse section 2 data when we don't know anything more
     516                 :  * about the data.
     517                 :  *
     518                 :  * ARGUMENTS
     519                 :  *  rdat = The float data in section 2. (Input)
     520                 :  * nrdat = Length of rdat. (Input)
     521                 :  *  idat = The integer data in section 2. (Input)
     522                 :  * nidat = Length of idat. (Input)
     523                 :  *  meta = The structure to fill. (Output)
     524                 :  *
     525                 :  * FILES/DATABASES: None
     526                 :  *
     527                 :  * RETURNS: int (could use errSprintf())
     528                 :  *  0 = OK
     529                 :  * -1 = nrdat or nidat is too small.
     530                 :  * -2 = unexpected values in rdat.
     531                 :  *
     532                 :  * HISTORY
     533                 :  *   2/2003 Arthur Taylor (MDL/RSIS): Created.
     534                 :  *
     535                 :  * NOTES
     536                 :  *   In the extremely improbable case that there is both idat data and rdat
     537                 :  *   data, we process the rdat data first.
     538                 :  *****************************************************************************
     539                 :  */
     540               0 : static int ParseSect2_Unknown (float *rdat, sInt4 nrdat, sInt4 *idat,
     541                 :                                sInt4 nidat, grib_MetaData *meta)
     542                 : {
     543                 :    /* Used for easier access to answer. */
     544                 :    int loc;             /* Where we currently are in idat. */
     545                 :    int ansLoc;          /* Where we are in the answer data structure. */
     546                 :    sInt4 groupLen;      /* Length of current group in idat. */
     547                 :    int j;               /* Counter over the length of the current group. */
     548                 : 
     549               0 :    meta->pds2.sect2.unknown.dataLen = 0;
     550               0 :    meta->pds2.sect2.unknown.data = NULL;
     551               0 :    ansLoc = 0;
     552                 : 
     553                 :    /* Work with rdat data. */
     554               0 :    loc = 0;
     555               0 :    if (nrdat <= loc) {
     556               0 :       errSprintf ("ERROR: Ran out of rdat data\n");
     557               0 :       return -1;
     558                 :    }
     559               0 :    groupLen = (sInt4) rdat[loc++];
     560               0 :    loc++;               /* Skip the decimal scale factor data. */
     561               0 :    if (nrdat <= loc + groupLen) {
     562               0 :       errSprintf ("ERROR: Ran out of rdat data\n");
     563               0 :       return -1;
     564                 :    }
     565               0 :    while (groupLen > 0) {
     566               0 :       meta->pds2.sect2.unknown.dataLen += groupLen;
     567                 :       meta->pds2.sect2.unknown.data = (double *)
     568                 :             realloc ((void *) meta->pds2.sect2.unknown.data,
     569               0 :                      meta->pds2.sect2.unknown.dataLen * sizeof (double));
     570               0 :       for (j = 0; j < groupLen; j++) {
     571               0 :          meta->pds2.sect2.unknown.data[ansLoc++] = rdat[loc++];
     572                 :       }
     573               0 :       if (nrdat <= loc) {
     574               0 :          groupLen = 0;
     575                 :       } else {
     576               0 :          groupLen = (sInt4) rdat[loc++];
     577               0 :          if (groupLen != 0) {
     578               0 :             loc++;      /* Skip the decimal scale factor data. */
     579               0 :             if (nrdat <= loc + groupLen) {
     580               0 :                errSprintf ("ERROR: Ran out of rdat data\n");
     581               0 :                return -1;
     582                 :             }
     583                 :          }
     584                 :       }
     585                 :    }
     586                 : 
     587                 :    /* Work with idat data. */
     588               0 :    loc = 0;
     589               0 :    if (nidat <= loc) {
     590               0 :       errSprintf ("ERROR: Ran out of idat data\n");
     591               0 :       return -1;
     592                 :    }
     593               0 :    groupLen = idat[loc++];
     594               0 :    loc++;               /* Skip the decimal scale factor data. */
     595               0 :    if (nidat <= loc + groupLen) {
     596               0 :       errSprintf ("ERROR: Ran out of idat data\n");
     597               0 :       return -1;
     598                 :    }
     599               0 :    while (groupLen > 0) {
     600               0 :       meta->pds2.sect2.unknown.dataLen += groupLen;
     601                 :       meta->pds2.sect2.unknown.data = (double *)
     602                 :             realloc ((void *) meta->pds2.sect2.unknown.data,
     603               0 :                      meta->pds2.sect2.unknown.dataLen * sizeof (double));
     604               0 :       for (j = 0; j < groupLen; j++) {
     605               0 :          meta->pds2.sect2.unknown.data[ansLoc++] = idat[loc++];
     606                 :       }
     607               0 :       if (nidat <= loc) {
     608               0 :          groupLen = 0;
     609                 :       } else {
     610               0 :          groupLen = idat[loc++];
     611               0 :          if (groupLen != 0) {
     612               0 :             loc++;      /* Skip the decimal scale factor data. */
     613               0 :             if (nidat <= loc + groupLen) {
     614               0 :                errSprintf ("ERROR: Ran out of idat data\n");
     615               0 :                return -1;
     616                 :             }
     617                 :          }
     618                 :       }
     619                 :    }
     620               0 :    return 0;
     621                 : }
     622                 : 
     623                 : /*****************************************************************************
     624                 :  * ParseSect3() --
     625                 :  *
     626                 :  * Arthur Taylor / MDL
     627                 :  *
     628                 :  * PURPOSE
     629                 :  *   To verify and parse section 3 data.
     630                 :  *
     631                 :  * ARGUMENTS
     632                 :  *  is3 = The unpacked section 3 array. (Input)
     633                 :  *  ns3 = The size of section 3. (Input)
     634                 :  * meta = The structure to fill. (Output)
     635                 :  *
     636                 :  * FILES/DATABASES: None
     637                 :  *
     638                 :  * RETURNS: int (could use errSprintf())
     639                 :  *  0 = OK
     640                 :  * -1 = ns3 is too small.
     641                 :  * -2 = unexpected values in is3.
     642                 :  * -3 = un-supported map Projection.
     643                 :  *
     644                 :  * HISTORY
     645                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
     646                 :  *   9/2003 AAT: Adjusted Radius Earth case 1,6 to be based on:
     647                 :  *          Y * 10^D = R
     648                 :  *          Where Y = original value, D is scale factor, R is scale value.
     649                 :  *   1/2004 AAT: Adjusted Radius Earth case 6 to always be 6371.229 km
     650                 :  *
     651                 :  * NOTES
     652                 :  * Need to add support for GS3_ORTHOGRAPHIC = 90,
     653                 :  *   GS3_EQUATOR_EQUIDIST = 110, GS3_AZIMUTH_RANGE = 120
     654                 :  *****************************************************************************
     655                 :  */
     656               2 : static int ParseSect3 (sInt4 *is3, sInt4 ns3, grib_MetaData *meta)
     657                 : {
     658                 :    double unit;         /* Used to convert from stored value to degrees
     659                 :                          * lat/lon. See GRIB2 Regulation 92.1.6 */
     660                 :    sInt4 angle;         /* For Lat/Lon, 92.1.6 may not hold, in which case,
     661                 :                          * angle != 0, and unit = angle/subdivision. */
     662                 :    sInt4 subdivision;   /* see angle explaination. */
     663                 : 
     664               2 :    if (ns3 < 14) {
     665               0 :       return -1;
     666                 :    }
     667               2 :    if (is3[4] != 3) {
     668               0 :       errSprintf ("ERROR IS3 not labeled correctly. %ld\n", is3[4]);
     669               0 :       return -2;
     670                 :    }
     671               2 :    if (is3[5] != 0) {
     672                 :       errSprintf ("Can not handle 'Source of Grid Definition' = %ld\n",
     673               0 :                   is3[5]);
     674               0 :       errSprintf ("Can only handle grids defined in Code table 3.1\n");
     675                 :       // return -3;
     676                 :    }
     677               2 :    meta->gds.numPts = is3[6];
     678               2 :    if ((is3[10] != 0) || (is3[11] != 0)) {
     679                 :       errSprintf ("Un-supported Map Projection.\n  All Supported "
     680               0 :                   "projections have 0 bytes following the template.\n");
     681                 :       // return -3;
     682                 :    }
     683               2 :    meta->gds.projType = (uChar) is3[12];
     684                 : 
     685                 :    // Don't refuse to convert the GRIB file if only the projection is unknown to us
     686                 :    /*
     687                 :    if ((is3[12] != GS3_LATLON) && (is3[12] != GS3_MERCATOR) &&
     688                 :        (is3[12] != GS3_POLAR) && (is3[12] != GS3_LAMBERT)) {
     689                 :       errSprintf ("Un-supported Map Projection %ld\n", is3[12]);
     690                 :       return -3;
     691                 :    }
     692                 :    */
     693                 : 
     694                 :    /*
     695                 :     * Handle variables common to the supported templates.
     696                 :     */
     697               2 :    if (ns3 < 38) {
     698               0 :       return -1;
     699                 :    }
     700                 :    /* Assert: is3[14] is the shape of the earth. */
     701               2 :    switch (is3[14]) {
     702                 :       case 0:
     703               0 :          meta->gds.f_sphere = 1;
     704               0 :          meta->gds.majEarth = 6367.47;
     705               0 :          meta->gds.minEarth = 6367.47;
     706               0 :          break;
     707                 :       case 6:
     708               0 :          meta->gds.f_sphere = 1;
     709               0 :          meta->gds.majEarth = 6371.229;
     710               0 :          meta->gds.minEarth = 6371.229;
     711               0 :          break;
     712                 :       case 1:
     713               2 :          meta->gds.f_sphere = 1;
     714                 :          /* Following assumes scale factor and scale value refer to
     715                 :           * scientific notation. */
     716                 :          /* Incorrect Assumption (9/8/2003): scale factor / value are based
     717                 :           * on: Y * 10^D = R, where Y = original value, D = scale factor, ___
     718                 :           * R = scale value. */
     719                 : 
     720               2 :          if ((is3[16] != GRIB2MISSING_s4) && (is3[15] != GRIB2MISSING_s1)) {
     721                 :             /* Assumes data is given in m (not km). */
     722               2 :             meta->gds.majEarth = is3[16] / (pow (10.0, is3[15]) * 1000.);
     723               2 :             meta->gds.minEarth = meta->gds.majEarth;
     724                 :          } else {
     725               0 :             errSprintf ("Missing info on radius of Earth.\n");
     726               0 :             return -2;
     727                 :          }
     728                 :          /* Check if our m assumption was valid. If it wasn't, they give us
     729                 :           * 6371 km, which we convert to 6.371 < 6.4 */
     730               2 :          if (meta->gds.majEarth < 6.4) {
     731               0 :             meta->gds.majEarth = meta->gds.majEarth * 1000.;
     732               0 :             meta->gds.minEarth = meta->gds.minEarth * 1000.;
     733                 :          }
     734               2 :          break;
     735                 :       case 2:
     736               0 :          meta->gds.f_sphere = 0;
     737               0 :          meta->gds.majEarth = 6378.160;
     738               0 :          meta->gds.minEarth = 6356.775;
     739               0 :          break;
     740                 :       case 4:
     741               0 :          meta->gds.f_sphere = 0;
     742               0 :          meta->gds.majEarth = 6378.137;
     743               0 :          meta->gds.minEarth = 6356.752314;
     744               0 :          break;
     745                 :       case 5:
     746               0 :          meta->gds.f_sphere = 0;
     747               0 :          meta->gds.majEarth = 6378.137;
     748               0 :          meta->gds.minEarth = 6356.7523;
     749               0 :          break;
     750                 :       case 3:
     751               0 :          meta->gds.f_sphere = 0;
     752                 :          /* Following assumes scale factor and scale value refer to
     753                 :           * scientific notation. */
     754                 :          /* Incorrect Assumption (9/8/2003): scale factor / value are based
     755                 :           * on: Y * 10^D = R, where Y = original value, D = scale factor, ___
     756                 :           * R = scale value. */
     757               0 :          if ((is3[21] != GRIB2MISSING_s4) && (is3[20] != GRIB2MISSING_s1) &&
     758               0 :              (is3[26] != GRIB2MISSING_s4) && (is3[25] != GRIB2MISSING_s1)) {
     759                 :             /* Assumes data is given in km (not m). */
     760               0 :             meta->gds.majEarth = is3[21] / (pow (10.0, is3[20]));
     761               0 :             meta->gds.minEarth = is3[26] / (pow (10.0, is3[25]));
     762                 :          } else {
     763               0 :             errSprintf ("Missing info on major / minor axis of Earth.\n");
     764               0 :             return -2;
     765                 :          }
     766                 :          /* Check if our km assumption was valid. If it wasn't, they give us
     767                 :           * 6371000 m, which is > 6400. */
     768               0 :          if (meta->gds.majEarth > 6400) {
     769               0 :             meta->gds.majEarth = meta->gds.majEarth / 1000.;
     770                 :          }
     771               0 :          if (meta->gds.minEarth > 6400) {
     772               0 :             meta->gds.minEarth = meta->gds.minEarth / 1000.;
     773                 :          }
     774               0 :          break;
     775                 :       case 7:
     776               0 :          meta->gds.f_sphere = 0;
     777                 :          /* Following assumes scale factor and scale value refer to
     778                 :           * scientific notation. */
     779                 :          /* Incorrect Assumption (9/8/2003): scale factor / value are based
     780                 :           * on: Y * 10^D = R, where Y = original value, D = scale factor, ___
     781                 :           * R = scale value. */
     782               0 :          if ((is3[21] != GRIB2MISSING_s4) && (is3[20] != GRIB2MISSING_s1) &&
     783               0 :              (is3[26] != GRIB2MISSING_s4) && (is3[25] != GRIB2MISSING_s1)) {
     784                 :             /* Assumes data is given in m (not km). */
     785               0 :             meta->gds.majEarth = is3[21] / (pow (10.0, is3[20]) * 1000.);
     786               0 :             meta->gds.minEarth = is3[26] / (pow (10.0, is3[25]) * 1000.);
     787                 :          } else {
     788               0 :             errSprintf ("Missing info on major / minor axis of Earth.\n");
     789               0 :             return -2;
     790                 :          }
     791                 :          /* Check if our m assumption was valid. If it wasn't, they give us
     792                 :           * 6371 km, which we convert to 6.371 < 6.4 */
     793               0 :          if (meta->gds.majEarth < 6.4) {
     794               0 :             meta->gds.majEarth = meta->gds.majEarth * 1000.;
     795                 :          }
     796               0 :          if (meta->gds.minEarth < 6.4) {
     797               0 :             meta->gds.minEarth = meta->gds.minEarth * 1000.;
     798                 :          }
     799               0 :          break;
     800                 :       default:
     801               0 :          errSprintf ("Undefined shape of earth? %ld\n", is3[14]);
     802               0 :          return -2;
     803                 :    }
     804                 :    /* Validate the radEarth is reasonable. */
     805               2 :    if ((meta->gds.majEarth > 6400) || (meta->gds.majEarth < 6300) ||
     806                 :        (meta->gds.minEarth > 6400) || (meta->gds.minEarth < 6300)) {
     807                 :       errSprintf ("Bad shape of earth? %f %f\n", meta->gds.majEarth,
     808               0 :                   meta->gds.minEarth);
     809               0 :       return -2;
     810                 :    }
     811               2 :    meta->gds.Nx = is3[30];
     812               2 :    meta->gds.Ny = is3[34];
     813               2 :    if (meta->gds.Nx * meta->gds.Ny != meta->gds.numPts) {
     814               0 :       errSprintf ("Nx * Ny != number of points?\n");
     815               0 :       return -2;
     816                 :    }
     817                 : 
     818                 :    /* Initialize variables prior to parsing the specific templates. */
     819               2 :    unit = 1e-6;
     820               2 :    meta->gds.center = 0;
     821               2 :    meta->gds.scaleLat1 = meta->gds.scaleLat2 = 0;
     822               2 :    meta->gds.southLat = meta->gds.southLon = 0;
     823               2 :    meta->gds.lat2 = meta->gds.lon2 = 0;
     824               2 :    switch (is3[12]) {
     825                 :       case GS3_LATLON: /* 0: Regular lat/lon grid. */
     826                 :       case GS3_GAUSSIAN_LATLON:  /* 40: Gaussian lat/lon grid. */
     827               0 :          if (ns3 < 72) {
     828               0 :             return -1;
     829                 :          }
     830               0 :          angle = is3[38];
     831               0 :          subdivision = is3[42];
     832               0 :          if (angle != 0) {
     833               0 :             if (subdivision == 0) {
     834                 :                errSprintf ("subdivision of 0? Could not determine unit"
     835               0 :                            " for latlon grid\n");
     836               0 :                return -2;
     837                 :             }
     838               0 :             unit = angle / (double) (subdivision);
     839                 :          }
     840               0 :          if ((is3[46] == GRIB2MISSING_s4) || (is3[50] == GRIB2MISSING_s4) ||
     841               0 :              (is3[55] == GRIB2MISSING_s4) || (is3[59] == GRIB2MISSING_s4) ||
     842               0 :              (is3[63] == GRIB2MISSING_s4) || (is3[67] == GRIB2MISSING_s4)) {
     843               0 :             errSprintf ("Lat/Lon grid is not defined completely.\n");
     844               0 :             return -2;
     845                 :          }
     846               0 :          meta->gds.lat1 = is3[46] * unit;
     847               0 :          meta->gds.lon1 = is3[50] * unit;
     848               0 :          meta->gds.resFlag = (uChar) is3[54];
     849               0 :          meta->gds.lat2 = is3[55] * unit;
     850               0 :          meta->gds.lon2 = is3[59] * unit;
     851               0 :          meta->gds.Dx = is3[63] * unit; /* degrees. */
     852               0 :          if (is3[12] == GS3_GAUSSIAN_LATLON) {
     853               0 :             int np = is3[67]; /* parallels between a pole and the equator */
     854               0 :             meta->gds.Dy = 90.0 / np;
     855                 :          } else
     856               0 :             meta->gds.Dy = is3[67] * unit; /* degrees. */
     857               0 :          meta->gds.scan = (uChar) is3[71];
     858               0 :          meta->gds.meshLat = 0;
     859               0 :          meta->gds.orientLon = 0;
     860                 :          /* Resolve resolution flag(bit 3,4).  Copy Dx,Dy as appropriate. */
     861               0 :          if ((meta->gds.resFlag & GRIB2BIT_3) &&
     862                 :              (!(meta->gds.resFlag & GRIB2BIT_4))) {
     863               0 :             meta->gds.Dy = meta->gds.Dx;
     864               0 :          } else if ((!(meta->gds.resFlag & GRIB2BIT_3)) &&
     865                 :                     (meta->gds.resFlag & GRIB2BIT_4)) {
     866               0 :             meta->gds.Dx = meta->gds.Dy;
     867                 :          }
     868               0 :          break;
     869                 :       case GS3_MERCATOR: /* 10: Mercator grid. */
     870               2 :          if (ns3 < 72) {
     871               0 :             return -1;
     872                 :          }
     873              10 :          if ((is3[38] == GRIB2MISSING_s4) || (is3[42] == GRIB2MISSING_s4) ||
     874               4 :              (is3[47] == GRIB2MISSING_s4) || (is3[51] == GRIB2MISSING_s4) ||
     875               4 :              (is3[55] == GRIB2MISSING_s4) || (is3[60] == GRIB2MISSING_s4)) {
     876               0 :             errSprintf ("Mercator grid is not defined completely.\n");
     877               0 :             return -2;
     878                 :          }
     879               2 :          meta->gds.lat1 = is3[38] * unit;
     880               2 :          meta->gds.lon1 = is3[42] * unit;
     881               2 :          meta->gds.resFlag = (uChar) is3[46];
     882               2 :          meta->gds.meshLat = is3[47] * unit;
     883               2 :          meta->gds.lat2 = is3[51] * unit;
     884               2 :          meta->gds.lon2 = is3[55] * unit;
     885               2 :          meta->gds.scan = (uChar) is3[59];
     886               2 :          meta->gds.orientLon = is3[60] * unit;
     887               2 :          meta->gds.Dx = is3[64] / 1000.; /* mm -> m */
     888               2 :          meta->gds.Dy = is3[68] / 1000.; /* mm -> m */
     889                 :          /* Resolve resolution flag(bit 3,4).  Copy Dx,Dy as appropriate. */
     890               2 :          if ((meta->gds.resFlag & GRIB2BIT_3) &&
     891                 :              (!(meta->gds.resFlag & GRIB2BIT_4))) {
     892               0 :             if (is3[64] == GRIB2MISSING_s4) {
     893               0 :                errSprintf ("Mercator grid is not defined completely.\n");
     894               0 :                return -2;
     895                 :             }
     896               0 :             meta->gds.Dy = meta->gds.Dx;
     897               2 :          } else if ((!(meta->gds.resFlag & GRIB2BIT_3)) &&
     898                 :                     (meta->gds.resFlag & GRIB2BIT_4)) {
     899               0 :             if (is3[68] == GRIB2MISSING_s4) {
     900               0 :                errSprintf ("Mercator grid is not defined completely.\n");
     901               0 :                return -2;
     902                 :             }
     903               0 :             meta->gds.Dx = meta->gds.Dy;
     904                 :          }
     905               2 :          break;
     906                 :       case GS3_POLAR:  /* 20: Polar Stereographic grid. */
     907               0 :          if (ns3 < 65) {
     908               0 :             return -1;
     909                 :          }
     910               0 :          if ((is3[38] == GRIB2MISSING_s4) || (is3[42] == GRIB2MISSING_s4) ||
     911               0 :              (is3[47] == GRIB2MISSING_s4) || (is3[51] == GRIB2MISSING_s4)) {
     912                 :             errSprintf ("Polar Stereographic grid is not defined "
     913               0 :                         "completely.\n");
     914               0 :             return -2;
     915                 :          }
     916               0 :          meta->gds.lat1 = is3[38] * unit;
     917               0 :          meta->gds.lon1 = is3[42] * unit;
     918               0 :          meta->gds.resFlag = (uChar) is3[46];
     919                 :          /* Note (1) resFlag (bit 3,4) not applicable. */
     920               0 :          meta->gds.meshLat = is3[47] * unit;
     921               0 :          meta->gds.orientLon = is3[51] * unit;
     922               0 :          meta->gds.Dx = is3[55] / 1000.; /* mm -> m */
     923               0 :          meta->gds.Dy = is3[59] / 1000.; /* mm -> m */
     924               0 :          meta->gds.center = (uChar) is3[63];
     925               0 :          if (meta->gds.center & GRIB2BIT_1) {
     926                 :             /* South polar stereographic. */
     927               0 :             meta->gds.scaleLat1 = meta->gds.scaleLat2 = -90;
     928                 :          } else {
     929                 :             /* North polar stereographic. */
     930               0 :             meta->gds.scaleLat1 = meta->gds.scaleLat2 = 90;
     931                 :          }
     932               0 :          if (meta->gds.center & GRIB2BIT_2) {
     933                 :             errSprintf ("Note (4) specifies no 'bi-polar stereograhic"
     934               0 :                         " projections'.\n");
     935               0 :             return -2;
     936                 :          }
     937               0 :          meta->gds.scan = (uChar) is3[64];
     938               0 :          break;
     939                 :       case GS3_LAMBERT: /* 30: Lambert Conformal grid. */
     940               0 :          if (ns3 < 81) {
     941               0 :             return -1;
     942                 :          }
     943               0 :          if ((is3[38] == GRIB2MISSING_s4) || (is3[42] == GRIB2MISSING_s4) ||
     944               0 :              (is3[47] == GRIB2MISSING_s4) || (is3[51] == GRIB2MISSING_s4) ||
     945               0 :              (is3[65] == GRIB2MISSING_s4) || (is3[69] == GRIB2MISSING_s4) ||
     946               0 :              (is3[73] == GRIB2MISSING_s4) || (is3[77] == GRIB2MISSING_s4)) {
     947                 :             errSprintf ("Lambert Conformal grid is not defined "
     948               0 :                         "completely.\n");
     949               0 :             return -2;
     950                 :          }
     951               0 :          meta->gds.lat1 = is3[38] * unit;
     952               0 :          meta->gds.lon1 = is3[42] * unit;
     953               0 :          meta->gds.resFlag = (uChar) is3[46];
     954                 :          /* Note (3) resFlag (bit 3,4) not applicable. */
     955               0 :          meta->gds.meshLat = is3[47] * unit;
     956               0 :          meta->gds.orientLon = is3[51] * unit;
     957               0 :          meta->gds.Dx = is3[55] / 1000.; /* mm -> m */
     958               0 :          meta->gds.Dy = is3[59] / 1000.; /* mm -> m */
     959               0 :          meta->gds.center = (uChar) is3[63];
     960               0 :          meta->gds.scan = (uChar) is3[64];
     961               0 :          meta->gds.scaleLat1 = is3[65] * unit;
     962               0 :          meta->gds.scaleLat2 = is3[69] * unit;
     963               0 :          meta->gds.southLat = is3[73] * unit;
     964               0 :          meta->gds.southLon = is3[77] * unit;
     965               0 :          break;
     966                 :       case GS3_ORTHOGRAPHIC: /* 90: Orthographic grid. */
     967                 :          // Misusing gdsType elements (gdsType needs extension)
     968               0 :          meta->gds.lat1 = is3[38];
     969               0 :          meta->gds.lon1 = is3[42];
     970               0 :          meta->gds.resFlag = (uChar) is3[46];
     971               0 :          meta->gds.Dx = is3[47];
     972               0 :          meta->gds.Dy = is3[51];
     973                 : 
     974               0 :          meta->gds.lon2 = is3[55] / 1000.; /* xp - X-coordinateSub-satellite, mm -> m */
     975               0 :          meta->gds.lat2 = is3[59] / 1000.; /* yp - Y-coordinateSub-satellite, mm -> m */
     976               0 :          meta->gds.scan = (uChar) is3[63];
     977               0 :          meta->gds.orientLon = is3[64]; /* angle */
     978               0 :          meta->gds.stretchFactor = is3[68] * 1000000.; /* altitude */
     979                 : 
     980               0 :          meta->gds.southLon = is3[72]; /* x0 - X-coordinateOrigin */
     981               0 :          meta->gds.southLat = is3[76]; /* y0 - Y-coordinateOrigin */
     982               0 :          break;
     983                 :       default:
     984               0 :          errSprintf ("Un-supported Map Projection. %ld\n", is3[12]);
     985                 :          // Don't abandon the conversion only because of an unknown projection
     986                 :          break;
     987                 :          //return -3;
     988                 :    }
     989               2 :    if (meta->gds.scan != GRIB2BIT_2) {
     990                 : #ifdef DEBUG
     991                 :       printf ("Scan mode is expected to be 0100 (ie %d) not %d\n",
     992                 :               GRIB2BIT_2, meta->gds.scan);
     993                 :       printf ("The merged GRIB2 Library should return it in 0100\n");
     994                 :       printf ("The merged library swaps both NCEP and MDL data to scan "
     995                 :               "mode 0100\n");
     996                 : #endif
     997                 : /*
     998                 :       errSprintf ("Scan mode is expected to be 0100 (ie %d) not %d",
     999                 :                   GRIB2BIT_2, meta->gds.scan);
    1000                 :       return -2;
    1001                 : */
    1002                 :    }
    1003               2 :    return 0;
    1004                 : }
    1005                 : 
    1006                 : /*****************************************************************************
    1007                 :  * ParseSect4Time2secV1() --
    1008                 :  *
    1009                 :  * Arthur Taylor / MDL
    1010                 :  *
    1011                 :  * PURPOSE
    1012                 :  *    Attempt to parse time data in units provided by GRIB1 table 4, to
    1013                 :  * seconds.
    1014                 :  *
    1015                 :  * ARGUMENTS
    1016                 :  * time = The delta time to convert. (Input)
    1017                 :  * unit = The unit to convert. (Input)
    1018                 :  *  ans = The converted answer. (Output)
    1019                 :  *
    1020                 :  * FILES/DATABASES: None
    1021                 :  *
    1022                 :  * RETURNS: int
    1023                 :  *  0 = OK
    1024                 :  * -1 = could not determine.
    1025                 :  *
    1026                 :  * HISTORY
    1027                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
    1028                 :  *   1/2005 AAT: Fixed unit2sec[] table to have element 10 be 10800 (3 hours)
    1029                 :  *          instead of 0.
    1030                 :  *
    1031                 :  * NOTES
    1032                 :  *****************************************************************************
    1033                 :  */
    1034              44 : int ParseSect4Time2secV1 (sInt4 time, int unit, double *ans)
    1035                 : {
    1036                 :    /* Following is a lookup table for unit conversion (see code table 4.4). */
    1037                 :    static sInt4 unit2sec[] = {
    1038                 :       60, 3600, 86400L, 0, 0,
    1039                 :       0, 0, 0, 0, 0,
    1040                 :       10800, 21600L, 43200L
    1041                 :    };
    1042              44 :    if ((unit >= 0) && (unit < 13)) {
    1043              44 :       if (unit2sec[unit] != 0) {
    1044              44 :          *ans = (double) (time * unit2sec[unit]);
    1045              44 :          return 0;
    1046                 :       }
    1047               0 :    } else if (unit == 254) {
    1048               0 :       *ans = (double) (time);
    1049               0 :       return 0;
    1050                 :    }
    1051               0 :    *ans = 0;
    1052               0 :    return -1;
    1053                 : }
    1054                 : 
    1055                 : /*****************************************************************************
    1056                 :  * ParseSect4Time2sec() --
    1057                 :  *
    1058                 :  * Arthur Taylor / MDL
    1059                 :  *
    1060                 :  * PURPOSE
    1061                 :  *    Attempt to parse time data in units provided by GRIB2 table 4.4, to
    1062                 :  * seconds.
    1063                 :  *
    1064                 :  * ARGUMENTS
    1065                 :  * time = The delta time to convert. (Input)
    1066                 :  * unit = The unit to convert. (Input)
    1067                 :  *  ans = The converted answer. (Output)
    1068                 :  *
    1069                 :  * FILES/DATABASES: None
    1070                 :  *
    1071                 :  * RETURNS: int
    1072                 :  *  0 = OK
    1073                 :  * -1 = could not determine.
    1074                 :  *
    1075                 :  * HISTORY
    1076                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
    1077                 :  *   1/2005 AAT: Fixed unit2sec[] table to have element 10 be 10800 (3 hours)
    1078                 :  *          instead of 0.
    1079                 :  *
    1080                 :  * NOTES
    1081                 :  *****************************************************************************
    1082                 :  */
    1083               4 : int ParseSect4Time2sec (sInt4 time, int unit, double *ans)
    1084                 : {
    1085                 :    /* Following is a lookup table for unit conversion (see code table 4.4). */
    1086                 :    static sInt4 unit2sec[] = {
    1087                 :       60, 3600, 86400L, 0, 0,
    1088                 :       0, 0, 0, 0, 0,
    1089                 :       10800, 21600L, 43200L, 1
    1090                 :    };
    1091               4 :    if ((unit >= 0) && (unit < 14)) {
    1092               4 :       if (unit2sec[unit] != 0) {
    1093               4 :          *ans = (double) (time * unit2sec[unit]);
    1094               4 :          return 0;
    1095                 :       }
    1096                 :    }
    1097               0 :    *ans = 0;
    1098               0 :    return -1;
    1099                 : }
    1100                 : 
    1101                 : /*****************************************************************************
    1102                 :  * ParseSect4() --
    1103                 :  *
    1104                 :  * Arthur Taylor / MDL
    1105                 :  *
    1106                 :  * PURPOSE
    1107                 :  *   To verify and parse section 4 data.
    1108                 :  *
    1109                 :  * ARGUMENTS
    1110                 :  *  is4 = The unpacked section 4 array. (Input)
    1111                 :  *  ns4 = The size of section 4. (Input)
    1112                 :  * meta = The structure to fill. (Output)
    1113                 :  *
    1114                 :  * FILES/DATABASES: None
    1115                 :  *
    1116                 :  * RETURNS: int (could use errSprintf())
    1117                 :  *  0 = OK
    1118                 :  * -1 = ns4 is too small.
    1119                 :  * -2 = unexpected values in is4.
    1120                 :  * -4 = un-supported Sect 4 template.
    1121                 :  * -5 = unsupported forecast time unit.
    1122                 :  * -6 = Ran out of memory.
    1123                 :  *
    1124                 :  * HISTORY
    1125                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
    1126                 :  *   3/2003 AAT: Added support for GS4_SATELLITE.
    1127                 :  *   3/2003 AAT: Adjusted allocing of sect4.Interval (should be safer now).
    1128                 :  *   9/2003 AAT: Adjusted interpretation of scale factor / value.
    1129                 :  *   5/2004 AAT: Added some memory checks.
    1130                 :  *   3/2005 AAT: Added a cast to (uChar) when comparing to GRIB2MISSING_1
    1131                 :  *   3/2005 AAT: Added GS4_PROBABIL_PNT.
    1132                 :  *
    1133                 :  * NOTES
    1134                 :  * Need to add support for GS4_RADAR = 20
    1135                 :  *****************************************************************************
    1136                 :  */
    1137               2 : static int ParseSect4 (sInt4 *is4, sInt4 ns4, grib_MetaData *meta)
    1138                 : {
    1139                 :    int i;               /* Counter for time intervals in template 4.8, 4.9
    1140                 :                          * (typically 1) or counter for satellite band in
    1141                 :                          * template 4.30. */
    1142                 :    void *temp_ptr;      /* A temporary pointer when reallocating memory. */
    1143                 :    char *msg;           /* A pointer to the current error message. */
    1144                 : 
    1145               2 :    if (ns4 < 9) {
    1146               0 :       return -1;
    1147                 :    }
    1148               2 :    if (is4[4] != 4) {
    1149                 : #ifdef DEBUG
    1150                 :       printf ("ERROR IS4 not labeled correctly. %d\n", is4[4]);
    1151                 : #endif
    1152               0 :       errSprintf ("ERROR IS4 not labeled correctly. %d\n", is4[4]);
    1153               0 :       return -2;
    1154                 :    }
    1155               2 :    if (is4[5] != 0) {
    1156                 : #ifdef DEBUG
    1157                 :       printf ("Un-supported template.\n  All Supported template "
    1158                 :               "have 0 coordinate vertical values after template.");
    1159                 : #endif
    1160                 :       errSprintf ("Un-supported template.\n  All Supported template "
    1161               0 :                   "have 0 coordinate vertical values after template.");
    1162               0 :       return -4;
    1163                 :    }
    1164               8 :    if ((is4[7] != GS4_ANALYSIS) && (is4[7] != GS4_ENSEMBLE) &&
    1165               4 :        (is4[7] != GS4_DERIVED) && (is4[7] != GS4_PROBABIL_PNT) &&
    1166               2 :        (is4[7] != GS4_STATISTIC) && (is4[7] != GS4_PROBABIL_TIME) &&
    1167               0 :        (is4[7] != GS4_PERCENTILE) && (is4[7] != GS4_ENSEMBLE_STAT) &&
    1168               0 :        (is4[7] != GS4_SATELLITE) && (is4[7] != GS4_DERIVED_INTERVAL)) {
    1169                 : #ifdef DEBUG
    1170                 :       printf ("Un-supported Template. %d\n", is4[7]);
    1171                 : #endif
    1172               0 :       errSprintf ("Un-supported Template. %d\n", is4[7]);
    1173               0 :       return -4;
    1174                 :    }
    1175               2 :    meta->pds2.sect4.templat = (unsigned short int) is4[7];
    1176                 : 
    1177                 :    /* 
    1178                 :     * Handle variables common to the supported templates.
    1179                 :     */
    1180               2 :    if (ns4 < 34) {
    1181               0 :       return -1;
    1182                 :    }
    1183               2 :    meta->pds2.sect4.cat = (uChar) is4[9];
    1184               2 :    meta->pds2.sect4.subcat = (uChar) is4[10];
    1185               2 :    meta->pds2.sect4.genProcess = (uChar) is4[11];
    1186                 : 
    1187                 :    /* Initialize variables prior to parsing the specific templates. */
    1188               2 :    meta->pds2.sect4.typeEnsemble = 0;
    1189               2 :    meta->pds2.sect4.perturbNum = 0;
    1190               2 :    meta->pds2.sect4.numberFcsts = 0;
    1191               2 :    meta->pds2.sect4.derivedFcst = 0;
    1192               2 :    meta->pds2.sect4.validTime = meta->pds2.refTime;
    1193                 : 
    1194               2 :    if (meta->pds2.sect4.templat == GS4_SATELLITE) {
    1195               0 :       meta->pds2.sect4.genID = (uChar) is4[12];
    1196               0 :       meta->pds2.sect4.numBands = (uChar) is4[13];
    1197                 :       meta->pds2.sect4.bands =
    1198                 :             (sect4_BandType *) realloc ((void *) meta->pds2.sect4.bands,
    1199                 :                                         meta->pds2.sect4.numBands *
    1200               0 :                                         sizeof (sect4_BandType));
    1201               0 :       for (i = 0; i < meta->pds2.sect4.numBands; i++) {
    1202               0 :          meta->pds2.sect4.bands[i].series =
    1203               0 :                (unsigned short int) is4[14 + 10 * i];
    1204               0 :          meta->pds2.sect4.bands[i].numbers =
    1205               0 :                (unsigned short int) is4[16 + 10 * i];
    1206               0 :          meta->pds2.sect4.bands[i].instType = (uChar) is4[18 + 10 * i];
    1207               0 :          meta->pds2.sect4.bands[i].centWaveNum.factor =
    1208               0 :                (uChar) is4[19 + 10 * i];
    1209               0 :          meta->pds2.sect4.bands[i].centWaveNum.value = is4[20 + 10 * i];
    1210                 :       }
    1211                 : 
    1212               0 :       meta->pds2.sect4.fstSurfType = GRIB2MISSING_u1;
    1213               0 :       meta->pds2.sect4.fstSurfScale = GRIB2MISSING_s1;
    1214               0 :       meta->pds2.sect4.fstSurfValue = 0;
    1215               0 :       meta->pds2.sect4.sndSurfType = GRIB2MISSING_u1;
    1216               0 :       meta->pds2.sect4.sndSurfScale = GRIB2MISSING_s1;
    1217               0 :       meta->pds2.sect4.sndSurfValue = 0;
    1218                 : 
    1219               0 :       return 0;
    1220                 :    }
    1221               2 :    meta->pds2.sect4.bgGenID = (uChar) is4[12];
    1222               2 :    meta->pds2.sect4.genID = (uChar) is4[13];
    1223               4 :    if ((is4[14] == GRIB2MISSING_u2) || (is4[16] == GRIB2MISSING_u1)) {
    1224               2 :       meta->pds2.sect4.f_validCutOff = 0;
    1225               2 :       meta->pds2.sect4.cutOff = 0;
    1226                 :    } else {
    1227               0 :       meta->pds2.sect4.f_validCutOff = 1;
    1228               0 :       meta->pds2.sect4.cutOff = is4[14] * 3600 + is4[16] * 60;
    1229                 :    }
    1230               2 :    if (is4[18] == GRIB2MISSING_s4) {
    1231               0 :       errSprintf ("Missing 'forecast' time?\n");
    1232               0 :       return -5;
    1233                 :    }
    1234               2 :    if (ParseSect4Time2sec (is4[18], is4[17],
    1235                 :                            &(meta->pds2.sect4.foreSec)) != 0) {
    1236               0 :       errSprintf ("Unable to convert this TimeUnit: %ld\n", is4[17]);
    1237               0 :       return -5;
    1238                 :    }
    1239                 : 
    1240                 :    meta->pds2.sect4.validTime = (time_t) (meta->pds2.refTime +
    1241               2 :                                           meta->pds2.sect4.foreSec);
    1242                 : 
    1243                 :    /*
    1244                 :     * Following is based on what was needed to get correct Radius of Earth in
    1245                 :     * section 3.  (Hopefully they are consistent).
    1246                 :     */
    1247               2 :    meta->pds2.sect4.fstSurfType = (uChar) is4[22];
    1248               2 :    if ((is4[24] == GRIB2MISSING_s4) || (is4[23] == GRIB2MISSING_s1) ||
    1249                 :        (meta->pds2.sect4.fstSurfType == GRIB2MISSING_u1)) {
    1250               0 :       meta->pds2.sect4.fstSurfScale = GRIB2MISSING_s1;
    1251               0 :       meta->pds2.sect4.fstSurfValue = 0;
    1252                 :    } else {
    1253               2 :       meta->pds2.sect4.fstSurfScale = is4[23];
    1254               2 :       meta->pds2.sect4.fstSurfValue = is4[24] / pow (10.0, is4[23]);
    1255                 :    }
    1256               2 :    meta->pds2.sect4.sndSurfType = (uChar) is4[28];
    1257               4 :    if ((is4[30] == GRIB2MISSING_s4) || (is4[29] == GRIB2MISSING_s1) ||
    1258                 :        (meta->pds2.sect4.sndSurfType == GRIB2MISSING_u1)) {
    1259               2 :       meta->pds2.sect4.sndSurfScale = GRIB2MISSING_s1;
    1260               2 :       meta->pds2.sect4.sndSurfValue = 0;
    1261                 :    } else {
    1262               0 :       meta->pds2.sect4.sndSurfScale = is4[29];
    1263               0 :       meta->pds2.sect4.sndSurfValue = is4[30] / pow (10.0, is4[29]);
    1264                 :    }
    1265               2 :    switch (meta->pds2.sect4.templat) {
    1266                 :       case GS4_ANALYSIS: /* 4.0 */
    1267               0 :          break;
    1268                 :       case GS4_ENSEMBLE: /* 4.1 */
    1269               0 :          meta->pds2.sect4.typeEnsemble = (uChar) is4[34];
    1270               0 :          meta->pds2.sect4.perturbNum = (uChar) is4[35];
    1271               0 :          meta->pds2.sect4.numberFcsts = (uChar) is4[36];
    1272               0 :          break;
    1273                 :       case GS4_ENSEMBLE_STAT: /* 4.1 */
    1274               0 :          meta->pds2.sect4.typeEnsemble = (uChar) is4[34];
    1275               0 :          meta->pds2.sect4.perturbNum = (uChar) is4[35];
    1276               0 :          meta->pds2.sect4.numberFcsts = (uChar) is4[36];
    1277               0 :          if (ParseTime (&(meta->pds2.sect4.validTime), is4[37], is4[39],
    1278               0 :                         is4[40], is4[41], is4[42], is4[43]) != 0) {
    1279               0 :             msg = errSprintf (NULL);
    1280               0 :             meta->pds2.sect4.numInterval = (uChar) is4[44];
    1281               0 :             if (meta->pds2.sect4.numInterval != 1) {
    1282                 :                errSprintf ("ERROR: in call to ParseTime from ParseSect4\n%s",
    1283               0 :                            msg);
    1284                 :                errSprintf ("Most likely they didn't complete bytes 38-44 of "
    1285               0 :                            "Template 4.11\n");
    1286               0 :                free (msg);
    1287               0 :                return -1;
    1288                 :             }
    1289               0 :             printf ("Warning: in call to ParseTime from ParseSect4\n%s", msg);
    1290               0 :             free (msg);
    1291                 :             meta->pds2.sect4.validTime = (time_t) (meta->pds2.refTime +
    1292               0 :                                                    meta->pds2.sect4.foreSec);
    1293                 :             printf ("Most likely they didn't complete bytes 38-44 of "
    1294               0 :                     "Template 4.11\n");
    1295                 :          } else {
    1296               0 :             meta->pds2.sect4.numInterval = (uChar) is4[44];
    1297                 :          }
    1298                 : 
    1299                 :          /* Added this check because some MOS grids didn't finish the
    1300                 :           * template. */
    1301               0 :          if (meta->pds2.sect4.numInterval != 0) {
    1302                 :             temp_ptr = realloc ((void *) meta->pds2.sect4.Interval,
    1303                 :                                 meta->pds2.sect4.numInterval *
    1304               0 :                                 sizeof (sect4_IntervalType));
    1305               0 :             if (temp_ptr == NULL) {
    1306               0 :                printf ("Ran out of memory.\n");
    1307               0 :                return -6;
    1308                 :             }
    1309               0 :             meta->pds2.sect4.Interval = (sect4_IntervalType *) temp_ptr;
    1310               0 :             meta->pds2.sect4.numMissing = is4[45];
    1311               0 :             for (i = 0; i < meta->pds2.sect4.numInterval; i++) {
    1312               0 :                meta->pds2.sect4.Interval[i].processID =
    1313               0 :                      (uChar) is4[49 + i * 12];
    1314               0 :                meta->pds2.sect4.Interval[i].incrType =
    1315               0 :                      (uChar) is4[50 + i * 12];
    1316               0 :                meta->pds2.sect4.Interval[i].timeRangeUnit =
    1317               0 :                      (uChar) is4[51 + i * 12];
    1318               0 :                meta->pds2.sect4.Interval[i].lenTime = is4[52 + i * 12];
    1319               0 :                meta->pds2.sect4.Interval[i].incrUnit =
    1320               0 :                      (uChar) is4[56 + i * 12];
    1321               0 :                meta->pds2.sect4.Interval[i].timeIncr =
    1322               0 :                      (uChar) is4[57 + i * 12];
    1323                 :             }
    1324                 :          } else {
    1325                 : #ifdef DEBUG
    1326                 :             printf ("Caution: Template 4.11 had no Intervals.\n");
    1327                 : #endif
    1328               0 :             meta->pds2.sect4.numMissing = is4[45];
    1329                 :          }
    1330               0 :          break;
    1331                 :       case GS4_DERIVED: /* 4.2 */
    1332               0 :          meta->pds2.sect4.derivedFcst = (uChar) is4[34];
    1333               0 :          meta->pds2.sect4.numberFcsts = (uChar) is4[35];
    1334               0 :          break;
    1335                 :       case GS4_DERIVED_INTERVAL: /* 4.12 */
    1336               0 :          meta->pds2.sect4.derivedFcst = (uChar) is4[34];
    1337               0 :          meta->pds2.sect4.numberFcsts = (uChar) is4[35];
    1338                 : 
    1339               0 :          if (ParseTime (&(meta->pds2.sect4.validTime), is4[36], is4[38],
    1340               0 :                         is4[39], is4[40], is4[41], is4[42]) != 0) {
    1341               0 :             msg = errSprintf (NULL);
    1342               0 :             meta->pds2.sect4.numInterval = (uChar) is4[43];
    1343               0 :             if (meta->pds2.sect4.numInterval != 1) {
    1344                 :                errSprintf ("ERROR: in call to ParseTime from ParseSect4\n%s",
    1345               0 :                            msg);
    1346                 :                errSprintf ("Most likely they didn't complete bytes 37-43 of "
    1347               0 :                            "Template 4.12\n");
    1348               0 :                free (msg);
    1349               0 :                return -1;
    1350                 :             }
    1351               0 :             printf ("Warning: in call to ParseTime from ParseSect4\n%s", msg);
    1352               0 :             free (msg);
    1353                 :             meta->pds2.sect4.validTime = (time_t) (meta->pds2.refTime +
    1354               0 :                                                    meta->pds2.sect4.foreSec);
    1355                 :             printf ("Most likely they didn't complete bytes 37-43 of "
    1356               0 :                     "Template 4.12\n");
    1357                 :          } else {
    1358               0 :             meta->pds2.sect4.numInterval = (uChar) is4[43];
    1359                 :          }
    1360                 : 
    1361                 :          /* Added this check because some MOS grids didn't finish the
    1362                 :           * template. */
    1363               0 :          if (meta->pds2.sect4.numInterval != 0) {
    1364                 :             temp_ptr = realloc ((void *) meta->pds2.sect4.Interval,
    1365                 :                                 meta->pds2.sect4.numInterval *
    1366               0 :                                 sizeof (sect4_IntervalType));
    1367               0 :             if (temp_ptr == NULL) {
    1368               0 :                printf ("Ran out of memory.\n");
    1369               0 :                return -6;
    1370                 :             }
    1371               0 :             meta->pds2.sect4.Interval = (sect4_IntervalType *) temp_ptr;
    1372               0 :             meta->pds2.sect4.numMissing = is4[44];
    1373               0 :             for (i = 0; i < meta->pds2.sect4.numInterval; i++) {
    1374               0 :                meta->pds2.sect4.Interval[i].processID =
    1375               0 :                      (uChar) is4[48 + i * 12];
    1376               0 :                meta->pds2.sect4.Interval[i].incrType =
    1377               0 :                      (uChar) is4[49 + i * 12];
    1378               0 :                meta->pds2.sect4.Interval[i].timeRangeUnit =
    1379               0 :                      (uChar) is4[50 + i * 12];
    1380               0 :                meta->pds2.sect4.Interval[i].lenTime = is4[51 + i * 12];
    1381               0 :                meta->pds2.sect4.Interval[i].incrUnit =
    1382               0 :                      (uChar) is4[55 + i * 12];
    1383               0 :                meta->pds2.sect4.Interval[i].timeIncr =
    1384               0 :                      (uChar) is4[56 + i * 12];
    1385                 :             }
    1386                 :          } else {
    1387                 : #ifdef DEBUG
    1388                 :             printf ("Caution: Template 4.12 had no Intervals.\n");
    1389                 : #endif
    1390               0 :             meta->pds2.sect4.numMissing = is4[44];
    1391                 :          }
    1392               0 :          break;
    1393                 :       case GS4_STATISTIC: /* 4.8 */
    1394               8 :          if (ParseTime (&(meta->pds2.sect4.validTime), is4[34], is4[36],
    1395               8 :                         is4[37], is4[38], is4[39], is4[40]) != 0) {
    1396               0 :             msg = errSprintf (NULL);
    1397               0 :             meta->pds2.sect4.numInterval = (uChar) is4[41];
    1398               0 :             if (meta->pds2.sect4.numInterval != 1) {
    1399                 :                errSprintf ("ERROR: in call to ParseTime from ParseSect4\n%s",
    1400               0 :                            msg);
    1401                 :                errSprintf ("Most likely they didn't complete bytes 35-41 of "
    1402               0 :                            "Template 4.8\n");
    1403               0 :                free (msg);
    1404               0 :                return -1;
    1405                 :             }
    1406               0 :             printf ("Warning: in call to ParseTime from ParseSect4\n%s", msg);
    1407               0 :             free (msg);
    1408                 :             meta->pds2.sect4.validTime = (time_t) (meta->pds2.refTime +
    1409               0 :                                                    meta->pds2.sect4.foreSec);
    1410                 :             printf ("Most likely they didn't complete bytes 35-41 of "
    1411               0 :                     "Template 4.8\n");
    1412                 :          } else {
    1413               2 :             meta->pds2.sect4.numInterval = (uChar) is4[41];
    1414                 :          }
    1415                 : 
    1416                 :          /* Added this check because some MOS grids didn't finish the
    1417                 :           * template. */
    1418               2 :          if (meta->pds2.sect4.numInterval != 0) {
    1419                 :             temp_ptr = realloc ((void *) meta->pds2.sect4.Interval,
    1420                 :                                 meta->pds2.sect4.numInterval *
    1421               2 :                                 sizeof (sect4_IntervalType));
    1422               2 :             if (temp_ptr == NULL) {
    1423               0 :                printf ("Ran out of memory.\n");
    1424               0 :                return -6;
    1425                 :             }
    1426               2 :             meta->pds2.sect4.Interval = (sect4_IntervalType *) temp_ptr;
    1427               2 :             meta->pds2.sect4.numMissing = is4[42];
    1428               4 :             for (i = 0; i < meta->pds2.sect4.numInterval; i++) {
    1429               2 :                meta->pds2.sect4.Interval[i].processID =
    1430               2 :                      (uChar) is4[46 + i * 12];
    1431               2 :                meta->pds2.sect4.Interval[i].incrType =
    1432               2 :                      (uChar) is4[47 + i * 12];
    1433               2 :                meta->pds2.sect4.Interval[i].timeRangeUnit =
    1434               2 :                      (uChar) is4[48 + i * 12];
    1435               2 :                meta->pds2.sect4.Interval[i].lenTime = is4[49 + i * 12];
    1436               2 :                meta->pds2.sect4.Interval[i].incrUnit =
    1437               2 :                      (uChar) is4[53 + i * 12];
    1438               2 :                meta->pds2.sect4.Interval[i].timeIncr =
    1439               2 :                      (uChar) is4[54 + i * 12];
    1440                 :             }
    1441                 :          } else {
    1442                 : #ifdef DEBUG
    1443                 :             printf ("Caution: Template 4.8 had no Intervals.\n");
    1444                 : #endif
    1445               0 :             meta->pds2.sect4.numMissing = is4[42];
    1446                 :          }
    1447               2 :          break;
    1448                 :       case GS4_PERCENTILE: /* 4.10 */
    1449               0 :          meta->pds2.sect4.percentile = is4[34];
    1450               0 :          if (ParseTime (&(meta->pds2.sect4.validTime), is4[35], is4[37],
    1451               0 :                         is4[38], is4[39], is4[40], is4[41]) != 0) {
    1452               0 :             msg = errSprintf (NULL);
    1453               0 :             meta->pds2.sect4.numInterval = (uChar) is4[42];
    1454               0 :             if (meta->pds2.sect4.numInterval != 1) {
    1455                 :                errSprintf ("ERROR: in call to ParseTime from ParseSect4\n%s",
    1456               0 :                            msg);
    1457                 :                errSprintf ("Most likely they didn't complete bytes 35-41 of "
    1458               0 :                            "Template 4.8\n");
    1459               0 :                free (msg);
    1460               0 :                return -1;
    1461                 :             }
    1462               0 :             printf ("Warning: in call to ParseTime from ParseSect4\n%s", msg);
    1463               0 :             free (msg);
    1464                 :             meta->pds2.sect4.validTime = (time_t) (meta->pds2.refTime +
    1465               0 :                                                    meta->pds2.sect4.foreSec);
    1466                 :             printf ("Most likely they didn't complete bytes 35-41 of "
    1467               0 :                     "Template 4.8\n");
    1468                 :          } else {
    1469               0 :             meta->pds2.sect4.numInterval = (uChar) is4[42];
    1470                 :          }
    1471                 : 
    1472                 :          /* Added this check because some MOS grids didn't finish the
    1473                 :           * template. */
    1474               0 :          if (meta->pds2.sect4.numInterval != 0) {
    1475                 :             temp_ptr = realloc ((void *) meta->pds2.sect4.Interval,
    1476                 :                                 meta->pds2.sect4.numInterval *
    1477               0 :                                 sizeof (sect4_IntervalType));
    1478               0 :             if (temp_ptr == NULL) {
    1479               0 :                printf ("Ran out of memory.\n");
    1480               0 :                return -6;
    1481                 :             }
    1482               0 :             meta->pds2.sect4.Interval = (sect4_IntervalType *) temp_ptr;
    1483               0 :             meta->pds2.sect4.numMissing = is4[43];
    1484               0 :             for (i = 0; i < meta->pds2.sect4.numInterval; i++) {
    1485               0 :                meta->pds2.sect4.Interval[i].processID =
    1486               0 :                      (uChar) is4[47 + i * 12];
    1487               0 :                meta->pds2.sect4.Interval[i].incrType =
    1488               0 :                      (uChar) is4[48 + i * 12];
    1489               0 :                meta->pds2.sect4.Interval[i].timeRangeUnit =
    1490               0 :                      (uChar) is4[49 + i * 12];
    1491               0 :                meta->pds2.sect4.Interval[i].lenTime = is4[50 + i * 12];
    1492               0 :                meta->pds2.sect4.Interval[i].incrUnit =
    1493               0 :                      (uChar) is4[54 + i * 12];
    1494               0 :                meta->pds2.sect4.Interval[i].timeIncr =
    1495               0 :                      (uChar) is4[55 + i * 12];
    1496                 :             }
    1497                 :          } else {
    1498                 : #ifdef DEBUG
    1499                 :             printf ("Caution: Template 4.10 had no Intervals.\n");
    1500                 : #endif
    1501               0 :             meta->pds2.sect4.numMissing = is4[43];
    1502                 :          }
    1503               0 :          break;
    1504                 :       case GS4_PROBABIL_PNT: /* 4.5 */
    1505               0 :          meta->pds2.sect4.foreProbNum = (uChar) is4[34];
    1506               0 :          meta->pds2.sect4.numForeProbs = (uChar) is4[35];
    1507               0 :          meta->pds2.sect4.probType = (uChar) is4[36];
    1508               0 :          meta->pds2.sect4.lowerLimit.factor = (sChar) is4[37];
    1509               0 :          meta->pds2.sect4.lowerLimit.value = is4[38];
    1510               0 :          meta->pds2.sect4.upperLimit.factor = (sChar) is4[42];
    1511               0 :          meta->pds2.sect4.upperLimit.value = is4[43];
    1512               0 :          break;
    1513                 :       case GS4_PROBABIL_TIME: /* 4.9 */
    1514               0 :          meta->pds2.sect4.foreProbNum = (uChar) is4[34];
    1515               0 :          meta->pds2.sect4.numForeProbs = (uChar) is4[35];
    1516               0 :          meta->pds2.sect4.probType = (uChar) is4[36];
    1517               0 :          meta->pds2.sect4.lowerLimit.factor = (sChar) is4[37];
    1518               0 :          meta->pds2.sect4.lowerLimit.value = is4[38];
    1519               0 :          meta->pds2.sect4.upperLimit.factor = (sChar) is4[42];
    1520               0 :          meta->pds2.sect4.upperLimit.value = is4[43];
    1521               0 :          if (ParseTime (&(meta->pds2.sect4.validTime), is4[47], is4[49],
    1522               0 :                         is4[50], is4[51], is4[52], is4[53]) != 0) {
    1523               0 :             msg = errSprintf (NULL);
    1524               0 :             meta->pds2.sect4.numInterval = (uChar) is4[54];
    1525               0 :             if (meta->pds2.sect4.numInterval != 1) {
    1526                 :                errSprintf ("ERROR: in call to ParseTime from ParseSect4\n%s",
    1527               0 :                            msg);
    1528                 :                errSprintf ("Most likely they didn't complete bytes 48-54 of "
    1529               0 :                            "Template 4.9\n");
    1530               0 :                free (msg);
    1531               0 :                return -1;
    1532                 :             }
    1533               0 :             printf ("Warning: in call to ParseTime from ParseSect4\n%s", msg);
    1534               0 :             free (msg);
    1535                 :             meta->pds2.sect4.validTime = (time_t) (meta->pds2.refTime +
    1536               0 :                                                    meta->pds2.sect4.foreSec);
    1537                 :             printf ("Most likely they didn't complete bytes 48-54 of "
    1538               0 :                     "Template 4.9\n");
    1539                 :          } else {
    1540               0 :             meta->pds2.sect4.numInterval = (uChar) is4[54];
    1541                 :          }
    1542                 :          temp_ptr = realloc ((void *) meta->pds2.sect4.Interval,
    1543                 :                              meta->pds2.sect4.numInterval *
    1544               0 :                              sizeof (sect4_IntervalType));
    1545               0 :          if (temp_ptr == NULL) {
    1546               0 :             printf ("Ran out of memory.\n");
    1547               0 :             return -6;
    1548                 :          }
    1549               0 :          meta->pds2.sect4.Interval = (sect4_IntervalType *) temp_ptr;
    1550               0 :          meta->pds2.sect4.numMissing = is4[55];
    1551               0 :          for (i = 0; i < meta->pds2.sect4.numInterval; i++) {
    1552               0 :             meta->pds2.sect4.Interval[i].processID = (uChar) is4[59 + i * 12];
    1553               0 :             meta->pds2.sect4.Interval[i].incrType = (uChar) is4[60 + i * 12];
    1554               0 :             meta->pds2.sect4.Interval[i].timeRangeUnit =
    1555               0 :                   (uChar) is4[61 + i * 12];
    1556               0 :             meta->pds2.sect4.Interval[i].lenTime = is4[62 + i * 12];
    1557               0 :             meta->pds2.sect4.Interval[i].incrUnit = (uChar) is4[66 + i * 12];
    1558               0 :             meta->pds2.sect4.Interval[i].timeIncr = (uChar) is4[67 + i * 12];
    1559                 :          }
    1560               0 :          break;
    1561                 :       default:
    1562               0 :          errSprintf ("Un-supported Template. %ld\n", is4[7]);
    1563               0 :          return -4;
    1564                 :    }
    1565               2 :    return 0;
    1566                 : }
    1567                 : 
    1568                 : /*****************************************************************************
    1569                 :  * ParseSect5() --
    1570                 :  *
    1571                 :  * Arthur Taylor / MDL
    1572                 :  *
    1573                 :  * PURPOSE
    1574                 :  *   To verify and parse section 5 data.
    1575                 :  *
    1576                 :  * ARGUMENTS
    1577                 :  *    is5 = The unpacked section 5 array. (Input)
    1578                 :  *    ns5 = The size of section 5. (Input)
    1579                 :  *   meta = The structure to fill. (Output)
    1580                 :  * xmissp = The primary missing value. (Input)
    1581                 :  * xmisss = The secondary missing value. (Input)
    1582                 :  *
    1583                 :  * FILES/DATABASES: None
    1584                 :  *
    1585                 :  * RETURNS: int (could use errSprintf())
    1586                 :  *  0 = OK
    1587                 :  * -1 = ns5 is too small.
    1588                 :  * -2 = unexpected values in is5.
    1589                 :  * -6 = unsupported packing.
    1590                 :  *
    1591                 :  * HISTORY
    1592                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
    1593                 :  *
    1594                 :  * NOTES
    1595                 :  *****************************************************************************
    1596                 :  */
    1597               2 : static int ParseSect5 (sInt4 *is5, sInt4 ns5, grib_MetaData *meta,
    1598                 :                        float xmissp, float xmisss)
    1599                 : {
    1600               2 :    if (ns5 < 22) {
    1601               0 :       return -1;
    1602                 :    }
    1603               2 :    if (is5[4] != 5) {
    1604               0 :       errSprintf ("ERROR IS5 not labeled correctly. %ld\n", is5[5]);
    1605               0 :       return -2;
    1606                 :    }
    1607               4 :    if ((is5[9] != GS5_SIMPLE) && (is5[9] != GS5_CMPLX) &&
    1608               2 :        (is5[9] != GS5_CMPLXSEC) && (is5[9] != GS5_SPECTRAL) &&
    1609               0 :        (is5[9] != GS5_HARMONIC) && (is5[9] != GS5_JPEG2000) &&
    1610               0 :        (is5[9] != GS5_PNG) && (is5[9] != GS5_JPEG2000_ORG) &&
    1611               0 :        (is5[9] != GS5_PNG_ORG)) {
    1612               0 :       errSprintf ("Un-supported Packing? %ld\n", is5[9]);
    1613               0 :       return -6;
    1614                 :    }
    1615               2 :    meta->gridAttrib.packType = (sInt4) is5[9];
    1616               2 :    meta->gridAttrib.f_maxmin = 0;
    1617               2 :    meta->gridAttrib.missPri = xmissp;
    1618               2 :    meta->gridAttrib.missSec = xmisss;
    1619               2 :    if ((is5[9] == GS5_SPECTRAL) || (is5[9] == GS5_HARMONIC)) {
    1620               0 :       meta->gridAttrib.fieldType = 0;
    1621               0 :       meta->gridAttrib.f_miss = 0;
    1622               0 :       return 0;
    1623                 :    }
    1624               2 :    if (is5[20] > 1) {
    1625               0 :       errSprintf ("Invalid field type. %ld\n", is5[20]);
    1626               0 :       return -2;
    1627                 :    }
    1628               2 :    MEMCPY_BIG (&meta->gridAttrib.refVal, &(is5[11]), 4);
    1629               2 :    meta->gridAttrib.ESF = is5[15];
    1630               2 :    meta->gridAttrib.DSF = is5[17];
    1631               2 :    meta->gridAttrib.fieldType = (uChar) is5[20];
    1632               6 :    if ((is5[9] == GS5_JPEG2000) || (is5[9] == GS5_JPEG2000_ORG) ||
    1633               4 :        (is5[9] == GS5_PNG) || (is5[9] == GS5_PNG_ORG)) {
    1634               0 :       meta->gridAttrib.f_miss = 0;
    1635               0 :       return 0;
    1636                 :    }
    1637               2 :    if (meta->gridAttrib.packType == 0) {
    1638               0 :       meta->gridAttrib.f_miss = 0;
    1639                 :    } else {
    1640               2 :       if (ns5 < 23) {
    1641               0 :          return -1;
    1642                 :       }
    1643               2 :       if (is5[22] > 2) {
    1644                 :          errSprintf ("Invalid missing management type, f_miss = %ld\n",
    1645               0 :                      is5[22]);
    1646               0 :          return -2;
    1647                 :       }
    1648               2 :       meta->gridAttrib.f_miss = (uChar) is5[22];
    1649                 :    }
    1650               2 :    return 0;
    1651                 : }
    1652                 : 
    1653                 : /*****************************************************************************
    1654                 :  * MetaParse() --
    1655                 :  *
    1656                 :  * Arthur Taylor / MDL
    1657                 :  *
    1658                 :  * PURPOSE
    1659                 :  *   To parse all the meta data from a grib2 message.
    1660                 :  *
    1661                 :  * ARGUMENTS
    1662                 :  *   meta = The structure to fill. (Output)
    1663                 :  *    is0 = The unpacked section 0 array. (Input)
    1664                 :  *    ns0 = The size of section 0. (Input)
    1665                 :  *    is1 = The unpacked section 1 array. (Input)
    1666                 :  *    ns1 = The size of section 1. (Input)
    1667                 :  *    is2 = The unpacked section 2 array. (Input)
    1668                 :  *    ns2 = The size of section 2. (Input)
    1669                 :  *   rdat = The float data in section 2. (Input)
    1670                 :  *  nrdat = Length of rdat. (Input)
    1671                 :  *   idat = The integer data in section 2. (Input)
    1672                 :  *  nidat = Length of idat. (Input)
    1673                 :  *    is3 = The unpacked section 3 array. (Input)
    1674                 :  *    ns3 = The size of section 3. (Input)
    1675                 :  *    is4 = The unpacked section 4 array. (Input)
    1676                 :  *    ns4 = The size of section 4. (Input)
    1677                 :  *    is5 = The unpacked section 5 array. (Input)
    1678                 :  *    ns5 = The size of section 5. (Input)
    1679                 :  * grib_len = The length of the entire grib message. (Input)
    1680                 :  * xmissp = The primary missing value. (Input)
    1681                 :  * xmisss = The secondary missing value. (Input)
    1682                 :  * simpVer = The version of the simple weather code to use when parsing the
    1683                 :  *           WxString (if applicable). (Input)
    1684                 :  *
    1685                 :  * FILES/DATABASES: None
    1686                 :  *
    1687                 :  * RETURNS: int (could use errSprintf())
    1688                 :  *   0 = OK
    1689                 :  *  -1 = A dimension is too small.
    1690                 :  *  -2 = unexpected values in a grib section.
    1691                 :  *  -3 = un-supported map Projection.
    1692                 :  *  -4 = un-supported Sect 4 template.
    1693                 :  *  -5 = unsupported forecast time unit.
    1694                 :  *  -6 = unsupported sect 5 packing.
    1695                 :  * -10 = Something the driver can't handle yet.
    1696                 :  *       (prodType != 0, f_sphere != 1, etc)
    1697                 :  * -11 = Weather grid without a lookup table.
    1698                 :  *
    1699                 :  * HISTORY
    1700                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
    1701                 :  *
    1702                 :  * NOTES
    1703                 :  *****************************************************************************
    1704                 :  */
    1705               2 : int MetaParse (grib_MetaData *meta, sInt4 *is0, sInt4 ns0,
    1706                 :                sInt4 *is1, sInt4 ns1, sInt4 *is2, sInt4 ns2,
    1707                 :                float *rdat, sInt4 nrdat, sInt4 *idat, sInt4 nidat,
    1708                 :                sInt4 *is3, sInt4 ns3, sInt4 *is4, sInt4 ns4,
    1709                 :                sInt4 *is5, sInt4 ns5, sInt4 grib_len,
    1710                 :                float xmissp, float xmisss, int simpVer)
    1711                 : {
    1712                 :    int ierr;            /* The error code of a called routine */
    1713                 :    /* char *element; *//* Holds the name of the current variable. */
    1714                 :    /* char *comment; *//* Holds more comments about current variable. */
    1715                 :    /* char *unitName; *//* Holds the name of the unit [K] [%] .. etc */
    1716                 :    uChar probType;      /* The probability type */
    1717                 :    double lowerProb;    /* The lower limit on probability forecast if
    1718                 :                          * template 4.5 or 4.9 */
    1719                 :    double upperProb;    /* The upper limit on probability forecast if
    1720                 :                          * template 4.5 or 4.9 */
    1721                 :    sInt4 lenTime;       /* Length of time for element (see 4.8 and 4.9) */
    1722                 : 
    1723               2 :    if ((ierr = ParseSect0 (is0, ns0, grib_len, meta)) != 0) {
    1724               0 :       preErrSprintf ("Parse error Section 0\n");
    1725                 :       //return ierr;
    1726                 :    }
    1727               2 :    if ((ierr = ParseSect1 (is1, ns1, meta)) != 0) {
    1728               0 :      preErrSprintf ("Parse error Section 1\n");
    1729                 :       //return ierr;
    1730                 :    }
    1731               2 :    if (ns2 < 7) {
    1732               0 :       errSprintf ("ns2 was too small in MetaParse\n");
    1733                 :       //return -1;
    1734                 :    }
    1735               2 :    meta->pds2.f_sect2 = (uChar) (is2[0] != 0);
    1736               2 :    if (meta->pds2.f_sect2) {
    1737               0 :       meta->pds2.sect2NumGroups = is2[7 - 1];
    1738                 :    } else {
    1739               2 :       meta->pds2.sect2NumGroups = 0;
    1740                 :    }
    1741               2 :    if ((ierr = ParseSect3 (is3, ns3, meta)) != 0) {
    1742               0 :       preErrSprintf ("Parse error Section 3\n");
    1743                 :       //return ierr;
    1744                 :    }
    1745               2 :    if (meta->gds.f_sphere != 1) {
    1746               0 :       errSprintf ("Driver Filter: Can only handle spheres.\n");
    1747                 :       //return -10;
    1748                 :    }
    1749               2 :    if ((ierr = ParseSect4 (is4, ns4, meta)) != 0) {
    1750               0 :       preErrSprintf ("Parse error Section 4\n");
    1751                 :       //return ierr;
    1752                 :    }
    1753               2 :    if ((ierr = ParseSect5 (is5, ns5, meta, xmissp, xmisss)) != 0) {
    1754               0 :       preErrSprintf ("Parse error Section 5\n");
    1755                 :       //return ierr;
    1756                 :    }
    1757                 :    /* Compute ElementName. */
    1758               2 :    if (meta->element) {
    1759               0 :       free (meta->element);
    1760               0 :       meta->element = NULL;
    1761                 :    }
    1762               2 :    if (meta->unitName) {
    1763               0 :       free (meta->unitName);
    1764               0 :       meta->unitName = NULL;
    1765                 :    }
    1766               2 :    if (meta->comment) {
    1767               0 :       free (meta->comment);
    1768               0 :       meta->comment = NULL;
    1769                 :    }
    1770                 : 
    1771               2 :    if ((meta->pds2.sect4.templat == GS4_PROBABIL_TIME) ||
    1772                 :        (meta->pds2.sect4.templat == GS4_PROBABIL_PNT)) {
    1773               0 :       probType = meta->pds2.sect4.probType;
    1774                 :       lowerProb = meta->pds2.sect4.lowerLimit.value *
    1775               0 :             pow (10.0, -1 * meta->pds2.sect4.lowerLimit.factor);
    1776                 :       upperProb = meta->pds2.sect4.upperLimit.value *
    1777               0 :             pow (10.0, -1 * meta->pds2.sect4.upperLimit.factor);
    1778                 :    } else {
    1779               2 :       probType = 0;
    1780               2 :       lowerProb = 0;
    1781               2 :       upperProb = 0;
    1782                 :    }
    1783               2 :    if (meta->pds2.sect4.numInterval > 0) {
    1784                 :       /* Try to convert lenTime to hourly. */
    1785               2 :       if (meta->pds2.sect4.Interval[0].timeRangeUnit == 255) {
    1786                 :          lenTime = (sInt4) ((meta->pds2.sect4.validTime -
    1787                 :                              meta->pds2.sect4.foreSec -
    1788               0 :                              meta->pds2.refTime) / 3600);
    1789               2 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 0) {
    1790               0 :           lenTime = (sInt4) (meta->pds2.sect4.Interval[0].lenTime / 60.);
    1791               2 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 1) {
    1792               2 :          lenTime = meta->pds2.sect4.Interval[0].lenTime;
    1793               0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 2) {
    1794               0 :          lenTime = meta->pds2.sect4.Interval[0].lenTime * 24;
    1795               0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 10) {
    1796               0 :          lenTime = meta->pds2.sect4.Interval[0].lenTime * 3;
    1797               0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 11) {
    1798               0 :          lenTime = meta->pds2.sect4.Interval[0].lenTime * 6;
    1799               0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 12) {
    1800               0 :          lenTime = meta->pds2.sect4.Interval[0].lenTime * 12;
    1801               0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 13) {
    1802               0 :          lenTime = (sInt4) (meta->pds2.sect4.Interval[0].lenTime / 3600.);
    1803                 :       } else {
    1804               0 :          lenTime = 0;
    1805               0 :          printf ("Can't handle this timeRangeUnit\n");
    1806                 :          myAssert (meta->pds2.sect4.Interval[0].timeRangeUnit == 1);
    1807                 :       }
    1808                 : /*
    1809                 :       } else {
    1810                 :          lenTime = 255;
    1811                 :       }
    1812                 :       if (lenTime == 255) {
    1813                 :          lenTime = (meta->pds2.sect4.validTime - meta->pds2.sect4.foreSec -
    1814                 :                     meta->pds2.refTime) / 3600;
    1815                 :       }
    1816                 : */
    1817               2 :       if (lenTime == GRIB2MISSING_s4) {
    1818               0 :          lenTime = 0;
    1819                 :       }
    1820                 :       ParseElemName (meta->center, meta->subcenter,
    1821                 :                      meta->pds2.prodType, meta->pds2.sect4.templat,
    1822                 :                      meta->pds2.sect4.cat, meta->pds2.sect4.subcat,
    1823               2 :                      lenTime, meta->pds2.sect4.Interval[0].incrType,
    1824                 :                      meta->pds2.sect4.genID, probType, lowerProb,
    1825                 :                      upperProb, &(meta->element), &(meta->comment),
    1826                 :                      &(meta->unitName), &(meta->convert),
    1827               4 :                      meta->pds2.sect4.percentile);
    1828                 :    } else {
    1829                 :       ParseElemName (meta->center, meta->subcenter,
    1830                 :                      meta->pds2.prodType, meta->pds2.sect4.templat,
    1831                 :                      meta->pds2.sect4.cat, meta->pds2.sect4.subcat, 0, 255,
    1832                 :                      meta->pds2.sect4.genID, probType, lowerProb, upperProb,
    1833                 :                      &(meta->element), &(meta->comment), &(meta->unitName),
    1834               0 :                      &(meta->convert), meta->pds2.sect4.percentile);
    1835                 :    }
    1836                 : #ifdef DEBUG
    1837                 : /*
    1838                 :    printf ("Element: %s\nunitName: %s\ncomment: %s\n", meta->element,
    1839                 :            meta->comment, meta->unitName);
    1840                 : */
    1841                 : #endif
    1842                 : 
    1843                 : /*
    1844                 :    if (strcmp (element, "") == 0) {
    1845                 :       meta->element = (char *) realloc ((void *) (meta->element),
    1846                 :                                         (1 + strlen ("unknown")) *
    1847                 :                                         sizeof (char));
    1848                 :       strcpy (meta->element, "unknown");
    1849                 :    } else {
    1850                 :       if (IsData_MOS (meta->pds2.center, meta->pds2.subcenter)) {
    1851                 :          * See : http://www.nco.ncep.noaa.gov/pmb/docs/on388/tablea.html *
    1852                 :          if (meta->pds2.sect4.genID == 96) {
    1853                 :             meta->element = (char *) realloc ((void *) (meta->element),
    1854                 :                                               (1 + 7 + strlen (element)) *
    1855                 :                                               sizeof (char));
    1856                 :             sprintf (meta->element, "MOSGFS-%s", element);
    1857                 :          } else {
    1858                 :             meta->element = (char *) realloc ((void *) (meta->element),
    1859                 :                                               (1 + 4 + strlen (element)) *
    1860                 :                                               sizeof (char));
    1861                 :             sprintf (meta->element, "MOS-%s", element);
    1862                 :          }
    1863                 :       } else {
    1864                 :          meta->element = (char *) realloc ((void *) (meta->element),
    1865                 :                                            (1 + strlen (element)) *
    1866                 :                                            sizeof (char));
    1867                 :          strcpy (meta->element, element);
    1868                 :       }
    1869                 :    }
    1870                 :    meta->unitName = (char *) realloc ((void *) (meta->unitName),
    1871                 :                                       (1 + 2 + strlen (unitName)) *
    1872                 :                                       sizeof (char));
    1873                 :    sprintf (meta->unitName, "[%s]", unitName);
    1874                 :    meta->comment = (char *) realloc ((void *) (meta->comment),
    1875                 :                                      (1 + strlen (comment) +
    1876                 :                                       strlen (unitName)
    1877                 :                                       + 2 + 1) * sizeof (char));
    1878                 :    sprintf (meta->comment, "%s [%s]", comment, unitName);
    1879                 : */
    1880               4 :    if ((meta->pds2.sect4.sndSurfScale == GRIB2MISSING_s1) ||
    1881                 :        (meta->pds2.sect4.sndSurfType == GRIB2MISSING_u1)) {
    1882                 : /*
    1883                 :       if ((meta->pds2.sect4.fstSurfScale == GRIB2MISSING_s1) ||
    1884                 :           (meta->pds2.sect4.fstSurfType == GRIB2MISSING_u1)) {
    1885                 :          ParseLevelName (meta->center, meta->subcenter,
    1886                 :                          meta->pds2.sect4.fstSurfType, 0, 0, 0,
    1887                 :                          &(meta->shortFstLevel), &(meta->longFstLevel));
    1888                 :       } else {
    1889                 : */
    1890                 :          ParseLevelName (meta->center, meta->subcenter,
    1891                 :                          meta->pds2.sect4.fstSurfType,
    1892                 :                          meta->pds2.sect4.fstSurfValue, 0, 0,
    1893               2 :                          &(meta->shortFstLevel), &(meta->longFstLevel));
    1894                 : /*
    1895                 :       }
    1896                 : */
    1897                 :    } else {
    1898                 :       ParseLevelName (meta->center, meta->subcenter,
    1899                 :                       meta->pds2.sect4.fstSurfType,
    1900                 :                       meta->pds2.sect4.fstSurfValue, 1,
    1901                 :                       meta->pds2.sect4.sndSurfValue, &(meta->shortFstLevel),
    1902               0 :                       &(meta->longFstLevel));
    1903                 :    }
    1904                 : 
    1905                 :    /* Continue parsing section 2 data. */
    1906               2 :    if (meta->pds2.f_sect2) {
    1907               0 :       MetaSect2Free (meta);
    1908               0 :       if (strcmp (meta->element, "Wx") == 0) {
    1909               0 :          meta->pds2.sect2.ptrType = GS2_WXTYPE;
    1910               0 :          if ((ierr = ParseSect2_Wx (rdat, nrdat, idat, nidat,
    1911                 :                                     &(meta->pds2.sect2.wx), simpVer)) != 0) {
    1912               0 :             preErrSprintf ("Parse error Section 2 : Weather Data\n");
    1913                 :             //return ierr;
    1914                 :          }
    1915                 :       } else {
    1916               0 :          meta->pds2.sect2.ptrType = GS2_UNKNOWN;
    1917               0 :          if ((ierr = ParseSect2_Unknown (rdat, nrdat, idat, nidat, meta))
    1918                 :              != 0) {
    1919               0 :             preErrSprintf ("Parse error Section 2 : Unknown Data type\n");
    1920                 :             //return ierr;
    1921                 :          }
    1922                 :       }
    1923                 :    } else {
    1924               2 :       if (strcmp (meta->element, "Wx") == 0) {
    1925               0 :          errSprintf ("Weather grid does not have look up table?");
    1926                 :          //return -11;
    1927                 :       }
    1928                 :    }
    1929               2 :    return 0;
    1930                 : }
    1931                 : 
    1932                 : /*****************************************************************************
    1933                 :  * ParseGridNoMiss() --
    1934                 :  *
    1935                 :  * Arthur Taylor / MDL
    1936                 :  *
    1937                 :  * PURPOSE
    1938                 :  *   A helper function for ParseGrid.  In this particular case it is dealing
    1939                 :  * with a field that has NO missing value type.
    1940                 :  *   Walks through either a float or an integer grid, computing the min/max
    1941                 :  * values in the grid, and converts the units. It uses gridAttrib info for the
    1942                 :  * missing values and it updates gridAttrib with the observed min/max values.
    1943                 :  *
    1944                 :  * ARGUMENTS
    1945                 :  *    attrib = Grid Attribute structure already filled in (Input/Output)
    1946                 :  * grib_Data = The place to store the grid data. (Output)
    1947                 :  *    Nx, Ny = The dimensions of the grid (Input)
    1948                 :  *      iain = Place to find data if it is an Integer (or float). (Input)
    1949                 :  *     unitM = M in unit conversion equation y(new) = m x(orig) + b (Input)
    1950                 :  *     unitB = B in unit conversion equation y(new) = m x(orig) + b (Input)
    1951                 :  *  f_wxType = true if we have a valid wx type. (Input)
    1952                 :  *    WxType = table to look up values in. (Input)
    1953                 :  *    startX = The start of the X values. (Input)
    1954                 :  *    startY = The start of the Y values. (Input)
    1955                 :  *     subNx = The Nx dimmension of the subgrid (Input)
    1956                 :  *     subNy = The Ny dimmension of the subgrid (Input)
    1957                 :  *
    1958                 :  * FILES/DATABASES: None
    1959                 :  *
    1960                 :  * RETURNS: void
    1961                 :  *
    1962                 :  * HISTORY
    1963                 :  *  12/2002 Arthur Taylor (MDL/RSIS): Created to optimize part of ParseGrid.
    1964                 :  *   5/2003 AAT: Added ability to see if wxType occurs.  If so sets table
    1965                 :  *          valid to 2, otherwise leaves it at 1.  If table valid is 0 then
    1966                 :  *          sets value to missing value (if applicable).
    1967                 :  *   2/2004 AAT: Added the subgrid capability.
    1968                 :  *
    1969                 :  * NOTES
    1970                 :  * 1) Don't have to check if value became missing value, because we can check
    1971                 :  *    if missing falls in the range of the min/max converted units.  If
    1972                 :  *    missing does fall in that range we need to move missing.
    1973                 :  *    (See f_readjust in ParseGrid)
    1974                 :  *****************************************************************************
    1975                 :  */
    1976               0 : static void ParseGridNoMiss (gridAttribType *attrib, double *grib_Data,
    1977                 :                              sInt4 Nx, sInt4 Ny, sInt4 *iain,
    1978                 :                              double unitM, double unitB, uChar f_wxType,
    1979                 :                              sect2_WxType *WxType, int startX, int startY,
    1980                 :                              int subNx, int subNy)
    1981                 : {
    1982                 :    sInt4 x, y;          /* Where we are in the grid. */
    1983                 :    double value;        /* The data in the new units. */
    1984               0 :    uChar f_maxmin = 0;  /* Flag if max/min is valid yet. */
    1985                 :    uInt4 index;         /* Current index into Wx table. */
    1986               0 :    sInt4 *itemp = NULL;
    1987               0 :    float *ftemp = NULL;
    1988                 : 
    1989                 :    /* Resolve possibility that the data is an integer or a float and find
    1990                 :     * max/min values. (see note 1) */
    1991               0 :    for (y = 0; y < subNy; y++) {
    1992               0 :       if (((startY + y - 1) < 0) || ((startY + y - 1) >= Ny)) {
    1993               0 :          for (x = 0; x < subNx; x++) {
    1994               0 :             *grib_Data++ = 9999;
    1995                 :          }
    1996                 :       } else {
    1997               0 :          if (attrib->fieldType) {
    1998               0 :             itemp = iain + (startY + y - 1) * Nx + (startX - 1);
    1999                 :          } else {
    2000               0 :             ftemp = ((float *) iain) + (startY + y - 1) * Nx + (startX - 1);
    2001                 :          }
    2002               0 :          for (x = 0; x < subNx; x++) {
    2003               0 :             if (((startX + x - 1) < 0) || ((startX + x - 1) >= Nx)) {
    2004               0 :                *grib_Data++ = 9999;
    2005                 :             } else {
    2006                 :                /* Convert the units. */
    2007               0 :                if (attrib->fieldType) {
    2008               0 :                   if (unitM == -10) {
    2009               0 :                      value = pow (10.0, (*itemp++));
    2010                 :                   } else {
    2011               0 :                      value = unitM * (*itemp++) + unitB;
    2012                 :                   }
    2013                 :                } else {
    2014               0 :                   if (unitM == -10) {
    2015               0 :                      value = pow (10.0, (double) (*ftemp++));
    2016                 :                   } else {
    2017               0 :                      value = unitM * (*ftemp++) + unitB;
    2018                 :                   }
    2019                 :                }
    2020               0 :                if (f_wxType) {
    2021               0 :                   index = (uInt4) value;
    2022               0 :                   if (index < WxType->dataLen) {
    2023               0 :                      if (WxType->ugly[index].f_valid == 1) {
    2024               0 :                         WxType->ugly[index].f_valid = 2;
    2025               0 :                      } else if (WxType->ugly[index].f_valid == 0) {
    2026                 :                         /* Table is not valid here so set value to missing? */
    2027                 :                         /* No missing value, so use index = WxType->dataLen? */
    2028                 :                         /* No... set f_valid to 3 so we know we used this
    2029                 :                          * invalid element, then handle it in degrib2.c ::
    2030                 :                          * ReadGrib2Record() where we set it back to 0. */
    2031               0 :                         WxType->ugly[index].f_valid = 3;
    2032                 :                      }
    2033                 :                   }
    2034                 :                }
    2035               0 :                if (f_maxmin) {
    2036               0 :                   if (value < attrib->min) {
    2037               0 :                      attrib->min = value;
    2038               0 :                   } else if (value > attrib->max) {
    2039               0 :                      attrib->max = value;
    2040                 :                   }
    2041                 :                } else {
    2042               0 :                   attrib->min = attrib->max = value;
    2043               0 :                   f_maxmin = 1;
    2044                 :                }
    2045               0 :                *grib_Data++ = value;
    2046                 :             }
    2047                 :          }
    2048                 :       }
    2049                 :    }
    2050               0 :    attrib->f_maxmin = f_maxmin;
    2051               0 : }
    2052                 : 
    2053                 : /*****************************************************************************
    2054                 :  * ParseGridPrimMiss() --
    2055                 :  *
    2056                 :  * Arthur Taylor / MDL
    2057                 :  *
    2058                 :  * PURPOSE
    2059                 :  *   A helper function for ParseGrid.  In this particular case it is dealing
    2060                 :  * with a field that has primary missing value type.
    2061                 :  *   Walks through either a float or an integer grid, computing the min/max
    2062                 :  * values in the grid, and converts the units. It uses gridAttrib info for the
    2063                 :  * missing values and it updates gridAttrib with the observed min/max values.
    2064                 :  *
    2065                 :  * ARGUMENTS
    2066                 :  *    attrib = sect 5 structure already filled in by ParseSect5 (In/Output)
    2067                 :  * grib_Data = The place to store the grid data. (Output)
    2068                 :  *    Nx, Ny = The dimensions of the grid (Input)
    2069                 :  *      iain = Place to find data if it is an Integer (or float). (Input)
    2070                 :  *     unitM = M in unit conversion equation y(new) = m x(orig) + b (Input)
    2071                 :  *     unitB = B in unit conversion equation y(new) = m x(orig) + b (Input)
    2072                 :  *  f_wxType = true if we have a valid wx type. (Input)
    2073                 :  *    WxType = table to look up values in. (Input)
    2074                 :  *    startX = The start of the X values. (Input)
    2075                 :  *    startY = The start of the Y values. (Input)
    2076                 :  *     subNx = The Nx dimmension of the subgrid (Input)
    2077                 :  *     subNy = The Ny dimmension of the subgrid (Input)
    2078                 :  *
    2079                 :  * FILES/DATABASES: None
    2080                 :  *
    2081                 :  * RETURNS: void
    2082                 :  *
    2083                 :  * HISTORY
    2084                 :  *  12/2002 Arthur Taylor (MDL/RSIS): Created to optimize part of ParseGrid.
    2085                 :  *   5/2003 AAT: Added ability to see if wxType occurs.  If so sets table
    2086                 :  *          valid to 2, otherwise leaves it at 1.  If table valid is 0 then
    2087                 :  *          sets value to missing value (if applicable).
    2088                 :  *   2/2004 AAT: Added the subgrid capability.
    2089                 :  *
    2090                 :  * NOTES
    2091                 :  * 1) Don't have to check if value became missing value, because we can check
    2092                 :  *    if missing falls in the range of the min/max converted units.  If
    2093                 :  *    missing does fall in that range we need to move missing.
    2094                 :  *    (See f_readjust in ParseGrid)
    2095                 :  *****************************************************************************
    2096                 :  */
    2097               2 : static void ParseGridPrimMiss (gridAttribType *attrib, double *grib_Data,
    2098                 :                                sInt4 Nx, sInt4 Ny, sInt4 *iain,
    2099                 :                                double unitM, double unitB, sInt4 *missCnt,
    2100                 :                                uChar f_wxType, sect2_WxType *WxType,
    2101                 :                                int startX, int startY, int subNx, int subNy)
    2102                 : {
    2103                 :    sInt4 x, y;          /* Where we are in the grid. */
    2104                 :    double value;        /* The data in the new units. */
    2105               2 :    uChar f_maxmin = 0;  /* Flag if max/min is valid yet. */
    2106                 :    uInt4 index;         /* Current index into Wx table. */
    2107               2 :    sInt4 *itemp = NULL;
    2108               2 :    float *ftemp = NULL;
    2109                 : /*   float *ain = (float *) iain;*/
    2110                 : 
    2111                 :    /* Resolve possibility that the data is an integer or a float and find
    2112                 :     * max/min values. (see note 1) */
    2113             260 :    for (y = 0; y < subNy; y++) {
    2114             258 :       if (((startY + y - 1) < 0) || ((startY + y - 1) >= Ny)) {
    2115               0 :          for (x = 0; x < subNx; x++) {
    2116               0 :             *grib_Data++ = attrib->missPri;
    2117               0 :             (*missCnt)++;
    2118                 :          }
    2119                 :       } else {
    2120             258 :          if (attrib->fieldType) {
    2121               0 :             itemp = iain + (startY + y - 1) * Nx + (startX - 1);
    2122                 :          } else {
    2123             258 :             ftemp = ((float *) iain) + (startY + y - 1) * Nx + (startX - 1);
    2124                 :          }
    2125           45924 :          for (x = 0; x < subNx; x++) {
    2126           45666 :             if (((startX + x - 1) < 0) || ((startX + x - 1) >= Nx)) {
    2127               0 :                *grib_Data++ = attrib->missPri;
    2128               0 :                (*missCnt)++;
    2129                 :             } else {
    2130           45666 :                if (attrib->fieldType) {
    2131               0 :                   value = (*itemp++);
    2132                 :                } else {
    2133           45666 :                   value = (*ftemp++);
    2134                 :                }
    2135                 : 
    2136                 :                /* Make sure value is not a missing value when converting
    2137                 :                 * units, and while computing max/min. */
    2138           45666 :                if (value == attrib->missPri) {
    2139            7512 :                   (*missCnt)++;
    2140                 :                } else {
    2141                 :                   /* Convert the units. */
    2142           38154 :                   if (unitM == -10) {
    2143               0 :                      value = pow (10.0, value);
    2144                 :                   } else {
    2145           38154 :                      value = unitM * value + unitB;
    2146                 :                   }
    2147           38154 :                   if (f_wxType) {
    2148               0 :                      index = (uInt4) value;
    2149               0 :                      if (index < WxType->dataLen) {
    2150               0 :                         if (WxType->ugly[index].f_valid) {
    2151               0 :                            WxType->ugly[index].f_valid = 2;
    2152                 :                         } else {
    2153                 :                            /* Table is not valid here so set value to missPri 
    2154                 :                             */
    2155               0 :                            value = attrib->missPri;
    2156               0 :                            (*missCnt)++;
    2157                 :                         }
    2158                 :                      }
    2159                 :                   }
    2160           38154 :                   if ((!f_wxType) || (value != attrib->missPri)) {
    2161           38154 :                      if (f_maxmin) {
    2162           38152 :                         if (value < attrib->min) {
    2163              30 :                            attrib->min = value;
    2164           38122 :                         } else if (value > attrib->max) {
    2165               0 :                            attrib->max = value;
    2166                 :                         }
    2167                 :                      } else {
    2168               2 :                         attrib->min = attrib->max = value;
    2169               2 :                         f_maxmin = 1;
    2170                 :                      }
    2171                 :                   }
    2172                 :                }
    2173           45666 :                *grib_Data++ = value;
    2174                 :             }
    2175                 :          }
    2176                 :       }
    2177                 :    }
    2178               2 :    attrib->f_maxmin = f_maxmin;
    2179               2 : }
    2180                 : 
    2181                 : /*****************************************************************************
    2182                 :  * ParseGridSecMiss() --
    2183                 :  *
    2184                 :  * Arthur Taylor / MDL
    2185                 :  *
    2186                 :  * PURPOSE
    2187                 :  *   A helper function for ParseGrid.  In this particular case it is dealing
    2188                 :  * with a field that has NO missing value type.
    2189                 :  *   Walks through either a float or an integer grid, computing the min/max
    2190                 :  * values in the grid, and converts the units. It uses gridAttrib info for the
    2191                 :  * missing values and it updates gridAttrib with the observed min/max values.
    2192                 :  *
    2193                 :  * ARGUMENTS
    2194                 :  *    attrib = sect 5 structure already filled in by ParseSect5 (In/Output)
    2195                 :  * grib_Data = The place to store the grid data. (Output)
    2196                 :  *    Nx, Ny = The dimensions of the grid (Input)
    2197                 :  *      iain = Place to find data if it is an Integer (or float). (Input)
    2198                 :  *     unitM = M in unit conversion equation y(new) = m x(orig) + b (Input)
    2199                 :  *     unitB = B in unit conversion equation y(new) = m x(orig) + b (Input)
    2200                 :  *  f_wxType = true if we have a valid wx type. (Input)
    2201                 :  *    WxType = table to look up values in. (Input)
    2202                 :  *    startX = The start of the X values. (Input)
    2203                 :  *    startY = The start of the Y values. (Input)
    2204                 :  *     subNx = The Nx dimmension of the subgrid (Input)
    2205                 :  *     subNy = The Ny dimmension of the subgrid (Input)
    2206                 :  *
    2207                 :  * FILES/DATABASES: None
    2208                 :  *
    2209                 :  * RETURNS: void
    2210                 :  *
    2211                 :  * HISTORY
    2212                 :  *  12/2002 Arthur Taylor (MDL/RSIS): Created to optimize part of ParseGrid.
    2213                 :  *   5/2003 AAT: Added ability to see if wxType occurs.  If so sets table
    2214                 :  *          valid to 2, otherwise leaves it at 1.  If table valid is 0 then
    2215                 :  *          sets value to missing value (if applicable).
    2216                 :  *   2/2004 AAT: Added the subgrid capability.
    2217                 :  *
    2218                 :  * NOTES
    2219                 :  * 1) Don't have to check if value became missing value, because we can check
    2220                 :  *    if missing falls in the range of the min/max converted units.  If
    2221                 :  *    missing does fall in that range we need to move missing.
    2222                 :  *    (See f_readjust in ParseGrid)
    2223                 :  *****************************************************************************
    2224                 :  */
    2225               0 : static void ParseGridSecMiss (gridAttribType *attrib, double *grib_Data,
    2226                 :                               sInt4 Nx, sInt4 Ny, sInt4 *iain,
    2227                 :                               double unitM, double unitB, sInt4 *missCnt,
    2228                 :                               uChar f_wxType, sect2_WxType *WxType,
    2229                 :                               int startX, int startY, int subNx, int subNy)
    2230                 : {
    2231                 :    sInt4 x, y;          /* Where we are in the grid. */
    2232                 :    double value;        /* The data in the new units. */
    2233               0 :    uChar f_maxmin = 0;  /* Flag if max/min is valid yet. */
    2234                 :    uInt4 index;         /* Current index into Wx table. */
    2235               0 :    sInt4 *itemp = NULL;
    2236               0 :    float *ftemp = NULL;
    2237                 : /*   float *ain = (float *) iain;*/
    2238                 : 
    2239                 :    /* Resolve possibility that the data is an integer or a float and find
    2240                 :     * max/min values. (see note 1) */
    2241               0 :    for (y = 0; y < subNy; y++) {
    2242               0 :       if (((startY + y - 1) < 0) || ((startY + y - 1) >= Ny)) {
    2243               0 :          for (x = 0; x < subNx; x++) {
    2244               0 :             *grib_Data++ = attrib->missPri;
    2245               0 :             (*missCnt)++;
    2246                 :          }
    2247                 :       } else {
    2248               0 :          if (attrib->fieldType) {
    2249               0 :             itemp = iain + (startY + y - 1) * Nx + (startX - 1);
    2250                 :          } else {
    2251               0 :             ftemp = ((float *) iain) + (startY + y - 1) * Nx + (startX - 1);
    2252                 :          }
    2253               0 :          for (x = 0; x < subNx; x++) {
    2254               0 :             if (((startX + x - 1) < 0) || ((startX + x - 1) >= Nx)) {
    2255               0 :                *grib_Data++ = attrib->missPri;
    2256               0 :                (*missCnt)++;
    2257                 :             } else {
    2258               0 :                if (attrib->fieldType) {
    2259               0 :                   value = (*itemp++);
    2260                 :                } else {
    2261               0 :                   value = (*ftemp++);
    2262                 :                }
    2263                 : 
    2264                 :                /* Make sure value is not a missing value when converting
    2265                 :                 * units, and while computing max/min. */
    2266               0 :                if ((value == attrib->missPri) || (value == attrib->missSec)) {
    2267               0 :                   (*missCnt)++;
    2268                 :                } else {
    2269                 :                   /* Convert the units. */
    2270               0 :                   if (unitM == -10) {
    2271               0 :                      value = pow (10.0, value);
    2272                 :                   } else {
    2273               0 :                      value = unitM * value + unitB;
    2274                 :                   }
    2275               0 :                   if (f_wxType) {
    2276               0 :                      index = (uInt4) value;
    2277               0 :                      if (index < WxType->dataLen) {
    2278               0 :                         if (WxType->ugly[index].f_valid) {
    2279               0 :                            WxType->ugly[index].f_valid = 2;
    2280                 :                         } else {
    2281                 :                            /* Table is not valid here so set value to missPri 
    2282                 :                             */
    2283               0 :                            value = attrib->missPri;
    2284               0 :                            (*missCnt)++;
    2285                 :                         }
    2286                 :                      }
    2287                 :                   }
    2288               0 :                   if ((!f_wxType) || (value != attrib->missPri)) {
    2289               0 :                      if (f_maxmin) {
    2290               0 :                         if (value < attrib->min) {
    2291               0 :                            attrib->min = value;
    2292               0 :                         } else if (value > attrib->max) {
    2293               0 :                            attrib->max = value;
    2294                 :                         }
    2295                 :                      } else {
    2296               0 :                         attrib->min = attrib->max = value;
    2297               0 :                         f_maxmin = 1;
    2298                 :                      }
    2299                 :                   }
    2300                 :                }
    2301               0 :                *grib_Data++ = value;
    2302                 :             }
    2303                 :          }
    2304                 :       }
    2305                 :    }
    2306               0 :    attrib->f_maxmin = f_maxmin;
    2307               0 : }
    2308                 : 
    2309                 : /*****************************************************************************
    2310                 :  * ParseGrid() --
    2311                 :  *
    2312                 :  * Arthur Taylor / MDL
    2313                 :  *
    2314                 :  * PURPOSE
    2315                 :  *   To walk through the 2 possible grids (and possible bitmap) created by
    2316                 :  * UNPK_GRIB2, and combine the info into 1 grid, at the same time computing
    2317                 :  * the min/max values in the grid.  It uses gridAttrib info for the missing values
    2318                 :  * and it then updates the gridAttrib structure for the min/max values that it
    2319                 :  * found.
    2320                 :  *   It also uses scan, and ScanIndex2XY, to parse the data and organize the
    2321                 :  * Grib_Data so that 0,0 is the lower left part of the grid, it then traverses
    2322                 :  * the row and then moved up to the next row starting on the left.
    2323                 :  *
    2324                 :  * ARGUMENTS
    2325                 :  *       attrib = sect 5 structure already filled in by ParseSect5 (In/Output)
    2326                 :  *    Grib_Data = The place to store the grid data. (Output)
    2327                 :  * grib_DataLen = The current size of Grib_Data (can increase) (Input/Output)
    2328                 :  *       Nx, Ny = The dimensions of the grid (Input)
    2329                 :  *         scan = How to walk through the original grid. (Input)
    2330                 :  *         iain = Place to find data if it is an Integer (or float). (Input)
    2331                 :  *      ibitmap = Flag stating the data has a bitmap for missing values (In)
    2332                 :  *           ib = Where to find the bitmap if we have one (Input)
    2333                 :  *        unitM = M in unit conversion equation y(new) = m x(orig) + b (Input)
    2334                 :  *        unitB = B in unit conversion equation y(new) = m x(orig) + b (Input)
    2335                 :  *     f_wxType = true if we have a valid wx type. (Input)
    2336                 :  *       WxType = table to look up values in. (Input)
    2337                 :  *    f_subGrid = True if we have a subgrid, false if not. (Input)
    2338                 :  * startX stopX = The bounds of the subgrid in X. (0,-1) means full grid (In)
    2339                 :  * startY stopY = The bounds of the subgrid in Y. (0,-1) means full grid (In)
    2340                 :  *
    2341                 :  * FILES/DATABASES: None
    2342                 :  *
    2343                 :  * RETURNS: void
    2344                 :  *
    2345                 :  * HISTORY
    2346                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
    2347                 :  *  11/2002 AAT: Added unit conversion to metaparse.c
    2348                 :  *  12/2002 AAT: Optimized first loop to make it assume scan 0100 (64)
    2349                 :  *         (valid 99.9%), but still have slow loop for generic case.
    2350                 :  *   5/2003 AAT: Added ability to see if wxType occurs.  If so sets table
    2351                 :  *          valid to 2, otherwise leaves it at 1.  If table valid is 0 then
    2352                 :  *          sets value to missing value (if applicable).
    2353                 :  *   7/2003 AAT: added check if f_maxmin before checking if missing was in
    2354                 :  *          range of max, min for "readjust" check.
    2355                 :  *   2/2004 AAT: Added startX / startY / stopX / stopY
    2356                 :  *   5/2004 AAT: Found out that I used the opposite definition for bitmap
    2357                 :  *          0 = missing, 1 = valid.
    2358                 :  *
    2359                 :  * NOTES
    2360                 :  *****************************************************************************
    2361                 :  */
    2362               2 : void ParseGrid (gridAttribType *attrib, double **Grib_Data,
    2363                 :                 uInt4 *grib_DataLen, uInt4 Nx, uInt4 Ny, int scan,
    2364                 :                 sInt4 *iain, sInt4 ibitmap, sInt4 *ib, double unitM,
    2365                 :                 double unitB, uChar f_wxType, sect2_WxType *WxType,
    2366                 :                 uChar f_subGrid, int startX, int startY, int stopX, int stopY)
    2367                 : {
    2368                 :    double xmissp;       /* computed missing value needed for ibitmap = 1,
    2369                 :                          * Also used if unit conversion causes confusion
    2370                 :                          * over_ missing values. */
    2371                 :    double xmisss;       /* Used if unit conversion causes confusion over
    2372                 :                          * missing values. */
    2373                 :    uChar f_readjust;    /* True if unit conversion caused confusion over
    2374                 :                          * missing values. */
    2375                 :    uInt4 scanIndex;     /* Where we are in the original grid. */
    2376                 :    sInt4 x, y;          /* Where we are in a grid of scan value 0100 */
    2377                 :    sInt4 newIndex;      /* x,y in a 1 dimensional array. */
    2378                 :    double value;        /* The data in the new units. */
    2379                 :    double *grib_Data;   /* A pointer to Grib_Data for ease of manipulation. */
    2380               2 :    sInt4 missCnt = 0;   /* Number of detected missing values. */
    2381                 :    uInt4 index;         /* Current index into Wx table. */
    2382               2 :    float *ain = (float *) iain;
    2383                 :    uInt4 subNx;         /* The Nx dimmension of the subgrid. */
    2384                 :    uInt4 subNy;         /* The Ny dimmension of the subgrid. */
    2385                 : 
    2386               2 :    subNx = stopX - startX + 1;
    2387               2 :    subNy = stopY - startY + 1;
    2388                 : 
    2389                 :    myAssert (((!f_subGrid) && (subNx == Nx)) || (f_subGrid));
    2390                 :    myAssert (((!f_subGrid) && (subNy == Ny)) || (f_subGrid));
    2391                 : 
    2392               2 :    if (subNx * subNy > *grib_DataLen) {
    2393               2 :       *grib_DataLen = subNx * subNy;
    2394                 :       *Grib_Data = (double *) realloc ((void *) (*Grib_Data),
    2395               2 :                                        (*grib_DataLen) * sizeof (double));
    2396                 :    }
    2397               2 :    grib_Data = *Grib_Data;
    2398                 : 
    2399                 :    /* Resolve possibility that the data is an integer or a float, find
    2400                 :     * max/min values, and do unit conversion. (see note 1) */
    2401               2 :    if (scan == 64) {
    2402               2 :       if (attrib->f_miss == 0) {
    2403                 :          ParseGridNoMiss (attrib, grib_Data, Nx, Ny, iain, unitM, unitB,
    2404               0 :                           f_wxType, WxType, startX, startY, subNx, subNy);
    2405               2 :       } else if (attrib->f_miss == 1) {
    2406                 :          ParseGridPrimMiss (attrib, grib_Data, Nx, Ny, iain, unitM, unitB,
    2407                 :                             &missCnt, f_wxType, WxType, startX, startY,
    2408               2 :                             subNx, subNy);
    2409               0 :       } else if (attrib->f_miss == 2) {
    2410                 :          ParseGridSecMiss (attrib, grib_Data, Nx, Ny, iain, unitM, unitB,
    2411                 :                            &missCnt, f_wxType, WxType, startX, startY, subNx,
    2412               0 :                            subNy);
    2413                 :       }
    2414                 :    } else {
    2415                 :       /* Internally we use scan = 0100.  Scan is usually 0100 from the
    2416                 :        * unpacker library, but if scan is not, the following code converts
    2417                 :        * it.  We optimized the previous (scan 0100) case by calling a
    2418                 :        * dedicated procedure.  Here we don't since for scan != 0100, we
    2419                 :        * would_ need a different unpacker library, which is extremely
    2420                 :        * unlikely. */
    2421               0 :       for (scanIndex = 0; scanIndex < Nx * Ny; scanIndex++) {
    2422               0 :          if (attrib->fieldType) {
    2423               0 :             value = iain[scanIndex];
    2424                 :          } else {
    2425               0 :             value = ain[scanIndex];
    2426                 :          }
    2427                 :          /* Make sure value is not a missing value when converting units, and 
    2428                 :           * while computing max/min. */
    2429               0 :          if ((attrib->f_miss == 0) ||
    2430                 :              ((attrib->f_miss == 1) && (value != attrib->missPri)) ||
    2431                 :              ((attrib->f_miss == 2) && (value != attrib->missPri) &&
    2432                 :               (value != attrib->missSec))) {
    2433                 :             /* Convert the units. */
    2434               0 :             if (unitM == -10) {
    2435               0 :                value = pow (10.0, value);
    2436                 :             } else {
    2437               0 :                value = unitM * value + unitB;
    2438                 :             }
    2439                 :             /* Don't have to check if value became missing value, because we
    2440                 :              * can check if missing falls in the range of min/max.  If
    2441                 :              * missing does fall in that range we need to move missing. See
    2442                 :              * f_readjust */
    2443               0 :             if (f_wxType) {
    2444               0 :                index = (uInt4) value;
    2445               0 :                if (index < WxType->dataLen) {
    2446               0 :                   if (WxType->ugly[index].f_valid == 1) {
    2447               0 :                      WxType->ugly[index].f_valid = 2;
    2448               0 :                   } else if (WxType->ugly[index].f_valid == 0) {
    2449                 :                      /* Table is not valid here so set value to missPri */
    2450               0 :                      if (attrib->f_miss != 0) {
    2451               0 :                         value = attrib->missPri;
    2452               0 :                         missCnt++;
    2453                 :                      } else {
    2454                 :                         /* No missing value, so use index = WxType->dataLen */
    2455                 :                         /* No... set f_valid to 3 so we know we used this
    2456                 :                          * invalid element, then handle it in degrib2.c ::
    2457                 :                          * ReadGrib2Record() where we set it back to 0. */
    2458               0 :                         WxType->ugly[index].f_valid = 3;
    2459                 :                      }
    2460                 :                   }
    2461                 :                }
    2462                 :             }
    2463               0 :             if ((!f_wxType) ||
    2464                 :                 ((attrib->f_miss == 0) || (value != attrib->missPri))) {
    2465               0 :                if (attrib->f_maxmin) {
    2466               0 :                   if (value < attrib->min) {
    2467               0 :                      attrib->min = value;
    2468               0 :                   } else if (value > attrib->max) {
    2469               0 :                      attrib->max = value;
    2470                 :                   }
    2471                 :                } else {
    2472               0 :                   attrib->min = attrib->max = value;
    2473               0 :                   attrib->f_maxmin = 1;
    2474                 :                }
    2475                 :             }
    2476                 :          } else {
    2477               0 :             missCnt++;
    2478                 :          }
    2479               0 :          ScanIndex2XY (scanIndex, &x, &y, scan, Nx, Ny);
    2480                 :          /* ScanIndex returns value as if scan was 0100 */
    2481               0 :          newIndex = (x - 1) + (y - 1) * Nx;
    2482               0 :          grib_Data[newIndex] = value;
    2483                 :       }
    2484                 :    }
    2485                 : 
    2486                 :    /* Deal with possibility that unit conversion ended up with valid numbers
    2487                 :     * being interpreted as missing. */
    2488               2 :    f_readjust = 0;
    2489               2 :    xmissp = attrib->missPri;
    2490               2 :    xmisss = attrib->missSec;
    2491               2 :    if (attrib->f_maxmin) {
    2492               2 :       if ((attrib->f_miss == 1) || (attrib->f_miss == 2)) {
    2493               2 :          if ((attrib->missPri >= attrib->min) &&
    2494                 :              (attrib->missPri <= attrib->max)) {
    2495               0 :             xmissp = attrib->max + 1;
    2496               0 :             f_readjust = 1;
    2497                 :          }
    2498               2 :          if (attrib->f_miss == 2) {
    2499               0 :             if ((attrib->missSec >= attrib->min) &&
    2500                 :                 (attrib->missSec <= attrib->max)) {
    2501               0 :                xmisss = attrib->max + 2;
    2502               0 :                f_readjust = 1;
    2503                 :             }
    2504                 :          }
    2505                 :       }
    2506                 :    }
    2507                 : 
    2508                 :    /* Walk through the grid, resetting the missing values, as determined by
    2509                 :     * the original grid. */
    2510               2 :    if (f_readjust) {
    2511               0 :       for (scanIndex = 0; scanIndex < Nx * Ny; scanIndex++) {
    2512               0 :          ScanIndex2XY (scanIndex, &x, &y, scan, Nx, Ny);
    2513                 :          /* ScanIndex returns value as if scan was 0100 */
    2514               0 :          newIndex = (x - 1) + (y - 1) * Nx;
    2515               0 :          if (attrib->fieldType) {
    2516               0 :             value = iain[scanIndex];
    2517                 :          } else {
    2518               0 :             value = ain[scanIndex];
    2519                 :          }
    2520               0 :          if (value == attrib->missPri) {
    2521               0 :             grib_Data[newIndex] = xmissp;
    2522               0 :          } else if ((attrib->f_miss == 2) && (value == attrib->missSec)) {
    2523               0 :             grib_Data[newIndex] = xmisss;
    2524                 :          }
    2525                 :       }
    2526               0 :       attrib->missPri = xmissp;
    2527               0 :       if (attrib->f_miss == 2) {
    2528               0 :          attrib->missSec = xmisss;
    2529                 :       }
    2530                 :    }
    2531                 : 
    2532                 :    /* Resolve bitmap (if there is one) in the data. */
    2533               2 :    if (ibitmap) {
    2534               0 :       attrib->f_maxmin = 0;
    2535               0 :       if ((attrib->f_miss != 1) && (attrib->f_miss != 2)) {
    2536               0 :          missCnt = 0;
    2537                 :          /* Figure out a missing value. */
    2538               0 :          xmissp = 9999;
    2539               0 :          if (attrib->f_maxmin) {
    2540               0 :             if ((xmissp <= attrib->max) && (xmissp >= attrib->min)) {
    2541               0 :                xmissp = attrib->max + 1;
    2542                 :             }
    2543                 :          }
    2544                 :          /* embed the missing value. */
    2545               0 :          for (scanIndex = 0; scanIndex < Nx * Ny; scanIndex++) {
    2546               0 :             ScanIndex2XY (scanIndex, &x, &y, scan, Nx, Ny);
    2547                 :             /* ScanIndex returns value as if scan was 0100 */
    2548               0 :             newIndex = (x - 1) + (y - 1) * Nx;
    2549                 :             /* Corrected this on 5/10/2004 */
    2550               0 :             if (ib[scanIndex] != 1) {
    2551               0 :                grib_Data[newIndex] = xmissp;
    2552               0 :                missCnt++;
    2553                 :             } else {
    2554               0 :                if (!attrib->f_maxmin) {
    2555               0 :                   attrib->f_maxmin = 1;
    2556               0 :                   attrib->max = attrib->min = grib_Data[newIndex];
    2557                 :                } else {
    2558               0 :                   if (attrib->max < grib_Data[newIndex])
    2559               0 :                      attrib->max = grib_Data[newIndex];
    2560               0 :                   if (attrib->min > grib_Data[newIndex])
    2561               0 :                      attrib->min = grib_Data[newIndex];
    2562                 :                }
    2563                 :             }
    2564                 :          }
    2565               0 :          attrib->f_miss = 1;
    2566               0 :          attrib->missPri = xmissp;
    2567                 :       }
    2568               0 :       if (!attrib->f_maxmin) {
    2569               0 :          attrib->f_maxmin = 1;
    2570               0 :          attrib->max = attrib->min = xmissp;
    2571                 :       }
    2572                 :    }
    2573               2 :    attrib->numMiss = missCnt;
    2574               2 : }
    2575                 : 
    2576                 : typedef struct {
    2577                 :    double value;
    2578                 :    int cnt;
    2579                 : } freqType;
    2580                 : 
    2581               0 : int freqCompare (const void *A, const void *B)
    2582                 : {
    2583               0 :    const freqType *a = (freqType *) A;
    2584               0 :    const freqType *b = (freqType *) B;
    2585                 : 
    2586               0 :    if (a->value < b->value)
    2587               0 :       return -1;
    2588               0 :    if (a->value > b->value)
    2589               0 :       return 1;
    2590               0 :    return 0;
    2591                 : }
    2592                 : 
    2593               0 : void FreqPrint (char **ans, double *Data, sInt4 DataLen, sInt4 Nx,
    2594                 :                 sInt4 Ny, sChar decimal, char *comment)
    2595                 : {
    2596                 :    int x, y, i;
    2597                 :    double *ptr;
    2598                 :    double value;
    2599               0 :    freqType *freq = NULL;
    2600               0 :    int numFreq = 0;
    2601                 :    char format[20];
    2602                 : 
    2603                 :    myAssert (*ans == NULL);
    2604                 : 
    2605               0 :    if ((Nx < 0) || (Ny < 0) || (Nx * Ny > DataLen)) {
    2606               0 :       return;
    2607                 :    }
    2608                 : 
    2609               0 :    ptr = Data;
    2610               0 :    for (y = 0; y < Ny; y++) {
    2611               0 :       for (x = 0; x < Nx; x++) {
    2612                 :          /* 2/28/2006 Introduced value to round before putting the data in
    2613                 :           * the Freq table. */
    2614               0 :          value = myRound (*ptr, decimal);
    2615               0 :          for (i = 0; i < numFreq; i++) {
    2616               0 :             if (value == freq[i].value) {
    2617               0 :                freq[i].cnt++;
    2618               0 :                break;
    2619                 :             }
    2620                 :          }
    2621               0 :          if (i == numFreq) {
    2622               0 :             numFreq++;
    2623               0 :             freq = (freqType *) realloc (freq, numFreq * sizeof (freqType));
    2624               0 :             freq[i].value = value;
    2625               0 :             freq[i].cnt = 1;
    2626                 :          }
    2627               0 :          ptr++;
    2628                 :       }
    2629                 :    }
    2630                 : 
    2631               0 :    qsort (freq, numFreq, sizeof (freq[0]), freqCompare);
    2632                 : 
    2633               0 :    mallocSprintf (ans, "%s | count\n", comment);
    2634               0 :    sprintf (format, "%%.%df | %%d\n", decimal);
    2635               0 :    for (i = 0; i < numFreq; i++) {
    2636               0 :       reallocSprintf (ans, format, myRound (freq[i].value, decimal),
    2637               0 :                       freq[i].cnt);
    2638                 :    }
    2639               0 :    free (freq);
    2640                 : }

Generated by: LCOV version 1.7