LCOV - code coverage report
Current view: top level - frmts/grib/degrib/degrib - metaparse.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 683 1544 44.2 %
Date: 2024-04-27 17:22:41 Functions: 17 22 77.3 %

          Line data    Source code
       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 <limits>
      22             : #include "clock.h"
      23             : #include "meta.h"
      24             : #include "metaname.h"
      25             : #include "myassert.h"
      26             : #include "myerror.h"
      27             : #include "scan.h"
      28             : #include "weather.h"
      29             : #include "hazard.h"
      30             : #include "tendian.h"
      31             : #include "myutil.h"
      32             : 
      33             : #include "cpl_string.h"
      34             : 
      35             : static void debug_printf(const char* fmt, ... ) CPL_PRINT_FUNC_FORMAT (1, 2);
      36             : 
      37          24 : static void debug_printf(const char* fmt, ... )
      38             : {
      39             :     va_list args;
      40             : 
      41          24 :     va_start( args, fmt );
      42          24 :     CPLDebug("GRIB", "%s", CPLString().vPrintf(fmt, args ).c_str() );
      43          24 :     va_end( args );
      44          24 : }
      45             : 
      46             : #undef printf
      47             : #define printf debug_printf
      48             : 
      49             : 
      50             : /*****************************************************************************
      51             :  * MetaInit() --
      52             :  *
      53             :  * Arthur Taylor / MDL
      54             :  *
      55             :  * PURPOSE
      56             :  *   To initialize a grib_metaData structure.
      57             :  *
      58             :  * ARGUMENTS
      59             :  * meta = The structure to fill. (Output)
      60             :  *
      61             :  * FILES/DATABASES: None
      62             :  *
      63             :  * RETURNS: void
      64             :  *
      65             :  * HISTORY
      66             :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
      67             :  *
      68             :  * NOTES
      69             :  *****************************************************************************
      70             :  */
      71         523 : void MetaInit (grib_MetaData *meta)
      72             : {
      73         523 :    meta->element = nullptr;
      74         523 :    meta->comment = nullptr;
      75         523 :    meta->unitName = nullptr;
      76         523 :    meta->convert = 0;
      77         523 :    meta->shortFstLevel = nullptr;
      78         523 :    meta->longFstLevel = nullptr;
      79         523 :    meta->pds2.sect2.ptrType = GS2_NONE;
      80             : 
      81         523 :    meta->pds2.sect2.wx.data = nullptr;
      82         523 :    meta->pds2.sect2.wx.dataLen = 0;
      83         523 :    meta->pds2.sect2.wx.maxLen = 0;
      84         523 :    meta->pds2.sect2.wx.ugly = nullptr;
      85         523 :    meta->pds2.sect2.unknown.data = nullptr;
      86         523 :    meta->pds2.sect2.unknown.dataLen = 0;
      87         523 :    meta->pds2.sect2.hazard.data = nullptr;
      88         523 :    meta->pds2.sect2.hazard.dataLen = 0;
      89         523 :    meta->pds2.sect2.hazard.maxLen = 0;
      90         523 :    meta->pds2.sect2.hazard.haz = nullptr;
      91             : 
      92         523 :    meta->pds2.sect4.numInterval = 0;
      93         523 :    meta->pds2.sect4.Interval = nullptr;
      94         523 :    meta->pds2.sect4.numBands = 0;
      95         523 :    meta->pds2.sect4.bands = nullptr;
      96         523 :    return;
      97             : }
      98             : 
      99             : /*****************************************************************************
     100             :  * MetaSect2Free() --
     101             :  *
     102             :  * Arthur Taylor / MDL
     103             :  *
     104             :  * PURPOSE
     105             :  *   To free the section 2 data in the grib_metaData structure.
     106             :  *
     107             :  * ARGUMENTS
     108             :  * meta = The structure to free. (Input/Output)
     109             :  *
     110             :  * FILES/DATABASES: None
     111             :  *
     112             :  * RETURNS: void
     113             :  *
     114             :  * HISTORY
     115             :  *   2/2003 Arthur Taylor (MDL/RSIS): Created.
     116             :  *   3/2003 AAT: Cleaned up declaration of variable: WxType.
     117             :  *
     118             :  * NOTES
     119             :  *****************************************************************************
     120             :  */
     121         525 : void MetaSect2Free (grib_MetaData *meta)
     122             : {
     123             :    size_t i;            /* Counter for use when freeing Wx data. */
     124             : 
     125         525 :    if (meta->pds2.sect2.ptrType == GS2_WXTYPE) {
     126           0 :       for (i = 0; i < meta->pds2.sect2.wx.dataLen; i++) {
     127           0 :          free (meta->pds2.sect2.wx.data[i]);
     128           0 :          FreeUglyString (&(meta->pds2.sect2.wx.ugly[i]));
     129             :       }
     130           0 :       free (meta->pds2.sect2.wx.ugly);
     131           0 :       meta->pds2.sect2.wx.ugly = nullptr;
     132           0 :       free (meta->pds2.sect2.wx.data);
     133           0 :       meta->pds2.sect2.wx.data = nullptr;
     134           0 :       free (meta->pds2.sect2.wx.f_valid);
     135           0 :       meta->pds2.sect2.wx.f_valid = nullptr;
     136           0 :       meta->pds2.sect2.wx.dataLen = 0;
     137           0 :       meta->pds2.sect2.wx.maxLen = 0;
     138         525 :    } else if (meta->pds2.sect2.ptrType == GS2_HAZARD) {
     139           0 :       for (i = 0; i < meta->pds2.sect2.hazard.dataLen; i++) {
     140           0 :          free (meta->pds2.sect2.hazard.data[i]);
     141           0 :          FreeHazardString (&(meta->pds2.sect2.hazard.haz[i]));
     142             :       }
     143           0 :       free (meta->pds2.sect2.hazard.haz);
     144           0 :       meta->pds2.sect2.hazard.haz = nullptr;
     145           0 :       free (meta->pds2.sect2.hazard.data);
     146           0 :       meta->pds2.sect2.hazard.data = nullptr;
     147           0 :       free (meta->pds2.sect2.hazard.f_valid);
     148           0 :       meta->pds2.sect2.hazard.f_valid = nullptr;
     149           0 :       meta->pds2.sect2.hazard.dataLen = 0;
     150           0 :       meta->pds2.sect2.hazard.maxLen = 0;
     151             :    } else {
     152         525 :       free (meta->pds2.sect2.unknown.data);
     153         525 :       meta->pds2.sect2.unknown.data = nullptr;
     154         525 :       meta->pds2.sect2.unknown.dataLen = 0;
     155             :    }
     156         525 :    meta->pds2.sect2.ptrType = GS2_NONE;
     157         525 : }
     158             : 
     159             : /*****************************************************************************
     160             :  * MetaFree() --
     161             :  *
     162             :  * Arthur Taylor / MDL
     163             :  *
     164             :  * PURPOSE
     165             :  *   To free a grib_metaData structure.
     166             :  *
     167             :  * ARGUMENTS
     168             :  * meta = The structure to free. (Output)
     169             :  *
     170             :  * FILES/DATABASES: None
     171             :  *
     172             :  * RETURNS: void
     173             :  *
     174             :  * HISTORY
     175             :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
     176             :  *
     177             :  * NOTES
     178             :  *****************************************************************************
     179             :  */
     180         523 : void MetaFree (grib_MetaData *meta)
     181             : {
     182         523 :    free (meta->pds2.sect4.bands);
     183         523 :    meta->pds2.sect4.bands = nullptr;
     184         523 :    meta->pds2.sect4.numBands = 0;
     185         523 :    free (meta->pds2.sect4.Interval);
     186         523 :    meta->pds2.sect4.Interval = nullptr;
     187         523 :    meta->pds2.sect4.numInterval = 0;
     188         523 :    MetaSect2Free (meta);
     189         523 :    free (meta->unitName);
     190         523 :    meta->unitName = nullptr;
     191         523 :    meta->convert = 0;
     192         523 :    free (meta->comment);
     193         523 :    meta->comment = nullptr;
     194         523 :    free (meta->element);
     195         523 :    meta->element = nullptr;
     196         523 :    free (meta->shortFstLevel);
     197         523 :    meta->shortFstLevel = nullptr;
     198         523 :    free (meta->longFstLevel);
     199         523 :    meta->longFstLevel = nullptr;
     200         523 : }
     201             : 
     202             : /*****************************************************************************
     203             :  * ParseTime() --
     204             :  *
     205             :  * Arthur Taylor / MDL
     206             :  *
     207             :  * PURPOSE
     208             :  *    To parse the time data from the grib2 integer array to a time_t in
     209             :  * UTC seconds from the epoch.
     210             :  *
     211             :  * ARGUMENTS
     212             :  * AnsTime = The time_t value to fill with the resulting time. (Output)
     213             :  *    year = The year to parse. (Input)
     214             :  *     mon = The month to parse. (Input)
     215             :  *     day = The day to parse. (Input)
     216             :  *    hour = The hour to parse. (Input)
     217             :  *     min = The minute to parse. (Input)
     218             :  *     sec = The second to parse. (Input)
     219             :  *
     220             :  * FILES/DATABASES: None
     221             :  *
     222             :  * RETURNS: int (could use errSprintf())
     223             :  *  0 = OK
     224             :  * -1 = gribLen is too small.
     225             :  *
     226             :  * HISTORY
     227             :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
     228             :  *   4/2003 AAT: Modified to use year/mon/day/hour/min/sec instead of an
     229             :  *               integer array.
     230             :  *   2/2004 AAT: Added error checks (because of corrupt GRIB1 files)
     231             :  *
     232             :  * NOTES
     233             :  * 1) Couldn't use the default time_zone variable (concern over portability
     234             :  *    issues), so we print the hours, and compare them to the hours we had
     235             :  *    intended.  Then subtract the difference from the AnsTime.
     236             :  * 2) Need error check for times outside of 1902..2037.
     237             :  *****************************************************************************
     238             :  */
     239         638 : int ParseTime (double *AnsTime, int year, uChar mon, uChar day, uChar hour,
     240             :                uChar min, uChar sec)
     241             : {
     242             :    /* struct tm time; *//* A temporary variable to put the time info into. */
     243             :    /* char buffer[10]; *//* Used when printing the AnsTime's Hr. */
     244             :    /* int timeZone; *//* The adjustment in Hr needed to get the right UTC * time. */
     245             : 
     246         638 :    if ((year < 1900) || (year > 2100)) {
     247           0 :       errSprintf ("ParseTime:: year %d is invalid\n", year);
     248             : /*      return -1; */
     249           0 :       year += 2000;
     250             :    }
     251             :    /* sec is allowed to be 61 for leap seconds. */
     252         638 :    if ((mon > 12) || (day == 0) || (day > 31) || (hour > 24) || (min > 60) ||
     253             :        (sec > 61)) {
     254           0 :       errSprintf ("ParseTime:: Problems with %d/%d %d:%d:%d\n", mon, day,
     255             :                   hour, min, sec);
     256           0 :       return -1;
     257             :    }
     258         638 :    Clock_ScanDate (AnsTime, year, mon, day);
     259         638 :    *AnsTime += hour * 3600. + min * 60. + sec;
     260             : /*   *AnsTime -= Clock_GetTimeZone() * 3600;*/
     261             : 
     262             : /*
     263             :    memset (&time, 0, sizeof (struct tm));
     264             :    time.tm_year = year - 1900;
     265             :    time.tm_mon = mon - 1;
     266             :    time.tm_mday = day;
     267             :    time.tm_hour = hour;
     268             :    time.tm_min = min;
     269             :    time.tm_sec = sec;
     270             :    printf ("%ld\n", mktime (&time));
     271             :    *AnsTime = mktime (&time) - (Clock_GetTimeZone () * 3600);
     272             : */
     273             :    /* Cheap method of getting global time_zone variable. */
     274             : /*
     275             :    strftime (buffer, 10, "%H", gmtime (AnsTime));
     276             :    timeZone = atoi (buffer) - hour;
     277             :    if (timeZone < 0) {
     278             :       timeZone += 24;
     279             :    }
     280             :    *AnsTime = *AnsTime - (timeZone * 3600);
     281             : */
     282         638 :    return 0;
     283             : }
     284             : 
     285             : /*****************************************************************************
     286             :  * ParseSect0() --
     287             :  *
     288             :  * Arthur Taylor / MDL
     289             :  *
     290             :  * PURPOSE
     291             :  *   To verify and parse section 0 data.
     292             :  *
     293             :  * ARGUMENTS
     294             :  *      is0 = The unpacked section 0 array. (Input)
     295             :  *      ns0 = The size of section 0. (Input)
     296             :  * grib_len = The length of the entire grib message. (Input)
     297             :  *     meta = The structure to fill. (Output)
     298             :  *
     299             :  * FILES/DATABASES: None
     300             :  *
     301             :  * RETURNS: int (could use errSprintf())
     302             :  *  0 = OK
     303             :  * -1 = ns0 is too small.
     304             :  * -2 = unexpected values in is0.
     305             :  *
     306             :  * HISTORY
     307             :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
     308             :  *
     309             :  * NOTES
     310             :  * 1) 1196575042L == ASCII representation of "GRIB"
     311             :  *****************************************************************************
     312             :  */
     313         457 : static int ParseSect0 (sInt4 *is0, sInt4 ns0, sInt4 grib_len,
     314             :                        grib_MetaData *meta)
     315             : {
     316         457 :    if (ns0 < 9) {
     317           0 :       return -1;
     318             :    }
     319         457 :    if ((is0[0] != 1196575042L) || (is0[7] != 2) || (is0[8] != grib_len)) {
     320           0 :       errSprintf ("ERROR IS0 has unexpected values: %ld %ld %ld\n",
     321           0 :                   is0[0], is0[7], is0[8]);
     322           0 :       errSprintf ("Should be %ld %d %ld\n", 1196575042L, 2, grib_len);
     323           0 :       return -2;
     324             :    }
     325         457 :    meta->pds2.prodType = (uChar) is0[6];
     326         457 :    return 0;
     327             : }
     328             : 
     329             : /*****************************************************************************
     330             :  * ParseSect1() --
     331             :  *
     332             :  * Arthur Taylor / MDL
     333             :  *
     334             :  * PURPOSE
     335             :  *   To verify and parse section 1 data.
     336             :  *
     337             :  * ARGUMENTS
     338             :  *  is1 = The unpacked section 1 array. (Input)
     339             :  *  ns1 = The size of section 1. (Input)
     340             :  * meta = The structure to fill. (Output)
     341             :  *
     342             :  * FILES/DATABASES: None
     343             :  *
     344             :  * RETURNS: int (could use errSprintf())
     345             :  *  0 = OK
     346             :  * -1 = ns1 is too small.
     347             :  * -2 = unexpected values in is1.
     348             :  *
     349             :  * HISTORY
     350             :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
     351             :  *
     352             :  * NOTES
     353             :  *****************************************************************************
     354             :  */
     355         457 : static int ParseSect1 (sInt4 *is1, sInt4 ns1, grib_MetaData *meta)
     356             : {
     357         457 :    if (ns1 < 21) {
     358           0 :       return -1;
     359             :    }
     360         457 :    if (is1[4] != 1) {
     361           0 :       errSprintf ("ERROR IS1 not labeled correctly. %ld\n", is1[4]);
     362           0 :       return -2;
     363             :    }
     364         457 :    meta->center = (unsigned short int) is1[5];
     365         457 :    meta->subcenter = (unsigned short int) is1[7];
     366         457 :    meta->pds2.mstrVersion = (uChar) is1[9];
     367         457 :    meta->pds2.lclVersion = (uChar) is1[10];
     368         457 :    if (((meta->pds2.mstrVersion < 1) || (meta->pds2.mstrVersion > 5)) ||
     369         447 :        (meta->pds2.lclVersion > 1)) {
     370          10 :       if (meta->pds2.mstrVersion == 0) {
     371           0 :          printf ("Warning: Master table version == 0, was experimental\n"
     372             :                  "I don't have a copy, and don't know where to get one\n"
     373             :                  "Use meta data at your own risk.\n");
     374          10 :       } else if (meta->pds2.mstrVersion != 255) {
     375           8 :          printf ("Warning: use meta data at your own risk.\n");
     376           8 :          printf ("Supported master table versions: (1,2,3,4,5) yours is %u... ",
     377           8 :                  meta->pds2.mstrVersion);
     378           8 :          printf ("Supported local table version supported (0,1) yours is %u...\n",
     379           8 :                  meta->pds2.lclVersion);
     380             :       }
     381             :    }
     382         457 :    meta->pds2.sigTime = (uChar) is1[11];
     383         914 :    if (ParseTime (&(meta->pds2.refTime), is1[12], is1[14], is1[15], is1[16],
     384         457 :                   is1[17], is1[18]) != 0) {
     385           0 :       preErrSprintf ("Error in call to ParseTime from ParseSect1 (GRIB2)");
     386           0 :       return -2;
     387             :    }
     388         457 :    meta->pds2.operStatus = (uChar) is1[19];
     389         457 :    meta->pds2.dataType = (uChar) is1[20];
     390         457 :    return 0;
     391             : }
     392             : 
     393             : /*****************************************************************************
     394             :  * ParseSect2_Wx() --
     395             :  *
     396             :  * Arthur Taylor / MDL
     397             :  *
     398             :  * PURPOSE
     399             :  *    To verify and parse section 2 data when we know the variable is of type
     400             :  * Wx (Weather).
     401             :  *
     402             :  * ARGUMENTS
     403             :  *    rdat = The float data in section 2. (Input)
     404             :  *   nrdat = Length of rdat. (Input)
     405             :  *    idat = The integer data in section 2. (Input)
     406             :  *   nidat = Length of idat. (Input)
     407             :  *      Wx = The weather structure to fill. (Output)
     408             :  * simpVer = The version of the simple weather code to use when parsing the
     409             :  *           WxString. (Input)
     410             :  *
     411             :  * FILES/DATABASES: None
     412             :  *
     413             :  * RETURNS: int (could use errSprintf())
     414             :  *  0 = OK
     415             :  * -1 = nrdat or nidat is too small.
     416             :  * -2 = unexpected values in rdat.
     417             :  *
     418             :  * HISTORY
     419             :  *   2/2003 Arthur Taylor (MDL/RSIS): Created.
     420             :  *   5/2003 AAT: Stopped messing around with the way buffer and data[i]
     421             :  *          were allocated.  It was confusing the free routine.
     422             :  *   5/2003 AAT: Added maxLen to Wx structure.
     423             :  *   6/2003 AAT: Revisited after Matt (matt@wunderground.com) informed me of
     424             :  *          memory problems.
     425             :  *          1) I had a memory leak caused by a buffer+= buffLen
     426             :  *          2) buffLen could have increased out of bounds of buffer.
     427             :  *   8/2003 AAT: Found an invalid "assertion" when dealing with non-NULL
     428             :  *          terminated weather groups.
     429             :  *
     430             :  * NOTES
     431             :  * 1) May want to rewrite so that we don't need 'meta->sect2NumGroups'
     432             :  *****************************************************************************
     433             :  */
     434           0 : static int ParseSect2_Wx (float *rdat, sInt4 nrdat, sInt4 *idat,
     435             :                           uInt4 nidat, sect2_WxType *Wx, int simpVer)
     436             : {
     437             :    size_t loc;          /* Where we currently are in idat. */
     438             :    size_t groupLen;     /* Length of current group in idat. */
     439             :    size_t j;            /* Counter over the length of the current group. */
     440             :    char *buffer;        /* Used to store the current "ugly" string. */
     441             :    int buffLen;         /* Length of current "ugly" string. */
     442             :    int len;             /* length of current English phrases during creation
     443             :                          * of the maxEng[] data. */
     444             :    int i;               /* assists in traversing the maxEng[] array. */
     445             : 
     446           0 :    if (nrdat < 1) {
     447           0 :       return -1;
     448             :    }
     449             : 
     450           0 :    if (rdat[0] != 0) {
     451           0 :       errSprintf ("ERROR: Expected rdat to be empty when dealing with "
     452             :                   "section 2 Weather data\n");
     453           0 :       return -2;
     454             :    }
     455           0 :    Wx->dataLen = 0;
     456           0 :    Wx->data = nullptr;
     457           0 :    Wx->maxLen = 0;
     458           0 :    for (i = 0; i < NUM_UGLY_WORD; i++) {
     459           0 :       Wx->maxEng[i] = 0;
     460             :    }
     461             : 
     462           0 :    loc = 0;
     463           0 :    if (nidat == 0) {
     464           0 :       errSprintf ("ERROR: Ran out of idat data\n");
     465           0 :       return -1;
     466             :    }
     467           0 :    groupLen = idat[loc++];
     468             : 
     469           0 :    loc++;               /* Skip the decimal scale factor data. */
     470             :    /* Note: This also assures that buffLen stays <= nidat. */
     471           0 :    if (loc + groupLen >= nidat) {
     472           0 :       errSprintf ("ERROR: Ran out of idat data\n");
     473           0 :       return -1;
     474             :    }
     475             : 
     476           0 :    buffLen = 0;
     477           0 :    buffer = (char *) malloc ((nidat + 1) * sizeof (char));
     478           0 :    while (groupLen > 0) {
     479           0 :       for (j = 0; j < groupLen; j++) {
     480           0 :          buffer[buffLen] = (char) idat[loc];
     481           0 :          buffLen++;
     482           0 :          loc++;
     483           0 :          if (buffer[buffLen - 1] == '\0') {
     484           0 :             Wx->dataLen++;
     485           0 :             Wx->data = (char **) realloc ((void *) Wx->data,
     486           0 :                                           Wx->dataLen * sizeof (char *));
     487             :             /* This is done after the realloc, just to make sure we have
     488             :              * enough memory allocated.  */
     489             :             /* Assert: buffLen is 1 more than strlen(buffer). */
     490           0 :             Wx->data[Wx->dataLen - 1] = (char *)
     491           0 :                   malloc (buffLen * sizeof (char));
     492           0 :             strcpy (Wx->data[Wx->dataLen - 1], buffer);
     493           0 :             if (Wx->maxLen < buffLen) {
     494           0 :                Wx->maxLen = buffLen;
     495             :             }
     496           0 :             buffLen = 0;
     497             :          }
     498             :       }
     499           0 :       if (loc >= nidat) {
     500           0 :          groupLen = 0;
     501             :       } else {
     502           0 :          groupLen = idat[loc];
     503           0 :          loc++;
     504           0 :          if (groupLen != 0) {
     505           0 :             loc++;      /* Skip the decimal scale factor data. */
     506             :             /* Note: This also assures that buffLen stays <= nidat. */
     507           0 :             if (loc + groupLen >= nidat) {
     508           0 :                errSprintf ("ERROR: Ran out of idat data\n");
     509           0 :                free (buffer);
     510           0 :                return -1;
     511             :             }
     512             :          }
     513             :       }
     514             :    }
     515           0 :    if (buffLen != 0) {
     516           0 :       buffer[buffLen] = '\0';
     517           0 :       Wx->dataLen++;
     518           0 :       Wx->data = (char **) realloc ((void *) Wx->data,
     519           0 :                                     Wx->dataLen * sizeof (char *));
     520             :       /* Assert: buffLen is 1 more than strlen(buffer). -- FALSE -- */
     521           0 :       buffLen = static_cast<int>(strlen (buffer)) + 1;
     522             : 
     523           0 :       Wx->data[Wx->dataLen - 1] = (char *) malloc (buffLen * sizeof (char));
     524           0 :       if (Wx->maxLen < buffLen) {
     525           0 :          Wx->maxLen = buffLen;
     526             :       }
     527           0 :       strcpy (Wx->data[Wx->dataLen - 1], buffer);
     528             :    }
     529           0 :    free (buffer);
     530           0 :    Wx->ugly = (UglyStringType *) malloc (Wx->dataLen *
     531             :                                          sizeof (UglyStringType));
     532           0 :    Wx->f_valid = (uChar *) malloc (Wx->dataLen * sizeof (uChar));
     533           0 :    for (j = 0; j < Wx->dataLen; j++) {
     534           0 :       if (ParseUglyString (&(Wx->ugly[j]), Wx->data[j], simpVer) == 0) {
     535           0 :          Wx->f_valid[j] = 1;
     536             :       } else {
     537           0 :          Wx->f_valid[j] = 0;
     538             :       }
     539             :    }
     540             :    /* We want to know how many bytes we need for each English phrase column,
     541             :     * so we walk through each column calculating that value. */
     542           0 :    for (i = 0; i < NUM_UGLY_WORD; i++) {
     543             :       /* Assert: Already initialized Wx->maxEng[i]. */
     544           0 :       for (j = 0; j < Wx->dataLen; j++) {
     545           0 :          if (Wx->ugly[j].english[i] != nullptr) {
     546           0 :             len = static_cast<int>(strlen (Wx->ugly[j].english[i]));
     547           0 :             if (len > Wx->maxEng[i]) {
     548           0 :                Wx->maxEng[i] = len;
     549             :             }
     550             :          }
     551             :       }
     552             :    }
     553           0 :    return 0;
     554             : }
     555             : 
     556           0 : static int ParseSect2_Hazard (float *rdat, sInt4 nrdat, sInt4 *idat,
     557             :                           uInt4 nidat, sect2_HazardType *Hazard, int simpWWA)
     558             : {
     559             :    size_t loc;          /* Where we currently are in idat. */
     560             :    size_t groupLen;     /* Length of current group in idat. */
     561             :    size_t j;            /* Counter over the length of the current group. */
     562             :    int len;             /* length of current english phrases during creation
     563             :                          * of the maxEng[] data. */
     564             :    int i;               /* assists in traversing the maxEng[] array. */
     565             :    char *buffer;        /* Used to store the current Hazard string. */
     566             :    int buffLen;         /* Length of current Hazard string. */
     567             : /*
     568             :    int k;
     569             : */
     570             : 
     571           0 :    if (nrdat < 1) {
     572           0 :       return -1;
     573             :    }
     574             : 
     575           0 :    if (rdat[0] != 0) {
     576           0 :       errSprintf ("ERROR: Expected rdat to be empty when dealing with "
     577             :                   "section 2 Weather data\n");
     578           0 :       return -2;
     579             :    }
     580           0 :    Hazard->dataLen = 0;
     581           0 :    Hazard->data = nullptr;
     582           0 :    Hazard->maxLen = 0;
     583           0 :    for (j = 0; j < NUM_HAZARD_WORD; j++) {
     584           0 :       Hazard->maxEng[j] = 0;
     585             :    }
     586             : 
     587           0 :    loc = 0;
     588           0 :    if (nidat == 0) {
     589           0 :       errSprintf ("ERROR: Ran out of idat data\n");
     590           0 :       return -1;
     591             :    }
     592           0 :    groupLen = idat[loc++];
     593             : 
     594           0 :    loc++;               /* Skip the decimal scale factor data. */
     595             :    /* Note: This also assures that buffLen stays <= nidat. */
     596           0 :    if (loc + groupLen >= nidat) {
     597           0 :       errSprintf ("ERROR: Ran out of idat data\n");
     598           0 :       return -1;
     599             :    }
     600             : 
     601           0 :    buffLen = 0;
     602           0 :    buffer = (char *) malloc ((nidat + 1) * sizeof (char));
     603           0 :    while (groupLen > 0) {
     604           0 :       for (j = 0; j < groupLen; j++) {
     605           0 :          buffer[buffLen] = (char) idat[loc];
     606           0 :          buffLen++;
     607           0 :          loc++;
     608           0 :          if (buffer[buffLen - 1] == '\0') {
     609           0 :             Hazard->dataLen++;
     610           0 :             Hazard->data = (char **) realloc ((void *) Hazard->data,
     611           0 :                                           Hazard->dataLen * sizeof (char *));
     612             :             /* This is done after the realloc, just to make sure we have
     613             :              * enough memory allocated.  */
     614             :             /* Assert: buffLen is 1 more than strlen(buffer). */
     615           0 :             Hazard->data[Hazard->dataLen - 1] = (char *)
     616           0 :                   malloc (buffLen * sizeof (char));
     617           0 :             strcpy (Hazard->data[Hazard->dataLen - 1], buffer);
     618           0 :             if (Hazard->maxLen < buffLen) {
     619           0 :                Hazard->maxLen = buffLen;
     620             :             }
     621           0 :             buffLen = 0;
     622             :          }
     623             :       }
     624           0 :       if (loc >= nidat) {
     625           0 :          groupLen = 0;
     626             :       } else {
     627           0 :          groupLen = idat[loc];
     628           0 :          loc++;
     629           0 :          if (groupLen != 0) {
     630           0 :             loc++;      /* Skip the decimal scale factor data. */
     631             :             /* Note: This also assures that buffLen stays <= nidat. */
     632           0 :             if (loc + groupLen >= nidat) {
     633           0 :                errSprintf ("ERROR: Ran out of idat data\n");
     634           0 :                free (buffer);
     635           0 :                return -1;
     636             :             }
     637             :          }
     638             :       }
     639             :    }
     640           0 :    if (buffLen != 0) {
     641           0 :       buffer[buffLen] = '\0';
     642           0 :       Hazard->dataLen++;
     643           0 :       Hazard->data = (char **) realloc ((void *) Hazard->data,
     644           0 :                                     Hazard->dataLen * sizeof (char *));
     645             :       /* Assert: buffLen is 1 more than strlen(buffer). -- FALSE -- */
     646           0 :       buffLen = static_cast<int>(strlen (buffer)) + 1;
     647             : 
     648           0 :       Hazard->data[Hazard->dataLen - 1] = (char *) malloc (buffLen * sizeof (char));
     649           0 :       if (Hazard->maxLen < buffLen) {
     650           0 :          Hazard->maxLen = buffLen;
     651             :       }
     652           0 :       strcpy (Hazard->data[Hazard->dataLen - 1], buffer);
     653             :    }
     654           0 :    free (buffer);
     655           0 :    Hazard->haz = (HazardStringType *) malloc (Hazard->dataLen *
     656             :                                          sizeof (HazardStringType));
     657           0 :    Hazard->f_valid = (uChar *) malloc (Hazard->dataLen * sizeof (uChar));
     658           0 :    for (j = 0; j < Hazard->dataLen; j++) {
     659           0 :       ParseHazardString (&(Hazard->haz[j]), Hazard->data[j], simpWWA);
     660           0 :       Hazard->f_valid[j] = 1;
     661             : /*
     662             :       printf ("%d : %d : %s", j, Hazard->haz[j].numValid, Hazard->data[j]);
     663             :       for (k = 0; k < Hazard->haz[j].numValid; k++) {
     664             :          printf (": %s", Hazard->haz[j].english[k]);
     665             :       }
     666             :       printf ("\n");
     667             : */
     668             :    }
     669             :    /* We want to know how many bytes we need for each english phrase column,
     670             :     * so we walk through each column calculating that value. */
     671           0 :    for (i = 0; i < NUM_HAZARD_WORD; i++) {
     672             :       /* Assert: Already initialized Hazard->maxEng[i]. */
     673           0 :       for (j = 0; j < Hazard->dataLen; j++) {
     674           0 :          if (Hazard->haz[j].english[i] != nullptr) {
     675           0 :             len = static_cast<int>(strlen (Hazard->haz[j].english[i]));
     676           0 :             if (len > Hazard->maxEng[i]) {
     677           0 :                Hazard->maxEng[i] = len;
     678             :             }
     679             :          }
     680             :       }
     681             :    }
     682           0 :    return 0;
     683             : }
     684             : 
     685             : /*****************************************************************************
     686             :  * ParseSect2_Unknown() --
     687             :  *
     688             :  * Arthur Taylor / MDL
     689             :  *
     690             :  * PURPOSE
     691             :  *    To verify and parse section 2 data when we don't know anything more
     692             :  * about the data.
     693             :  *
     694             :  * ARGUMENTS
     695             :  *  rdat = The float data in section 2. (Input)
     696             :  * nrdat = Length of rdat. (Input)
     697             :  *  idat = The integer data in section 2. (Input)
     698             :  * nidat = Length of idat. (Input)
     699             :  *  meta = The structure to fill. (Output)
     700             :  *
     701             :  * FILES/DATABASES: None
     702             :  *
     703             :  * RETURNS: int (could use errSprintf())
     704             :  *  0 = OK
     705             :  * -1 = nrdat or nidat is too small.
     706             :  * -2 = unexpected values in rdat.
     707             :  *
     708             :  * HISTORY
     709             :  *   2/2003 Arthur Taylor (MDL/RSIS): Created.
     710             :  *
     711             :  * NOTES
     712             :  *   In the extremely improbable case that there is both idat data and rdat
     713             :  *   data, we process the rdat data first.
     714             :  *****************************************************************************
     715             :  */
     716           2 : static int ParseSect2_Unknown (float *rdat, sInt4 nrdat, sInt4 *idat,
     717             :                                sInt4 nidat, grib_MetaData *meta)
     718             : {
     719             :    /* Used for easier access to answer. */
     720             :    int loc;             /* Where we currently are in idat. */
     721             :    int ansLoc;          /* Where we are in the answer data structure. */
     722             :    sInt4 groupLen;      /* Length of current group in idat. */
     723             :    int j;               /* Counter over the length of the current group. */
     724             : 
     725           2 :    meta->pds2.sect2.unknown.dataLen = 0;
     726           2 :    meta->pds2.sect2.unknown.data = nullptr;
     727           2 :    ansLoc = 0;
     728             : 
     729             :    /* Work with rdat data. */
     730           2 :    loc = 0;
     731           2 :    if (nrdat <= loc) {
     732           0 :       errSprintf ("ERROR: Ran out of rdat data\n");
     733           0 :       return -1;
     734             :    }
     735           2 :    groupLen = (sInt4) rdat[loc++];
     736           2 :    loc++;               /* Skip the decimal scale factor data. */
     737           2 :    if (nrdat <= loc + groupLen) {
     738           0 :       errSprintf ("ERROR: Ran out of rdat data\n");
     739           0 :       return -1;
     740             :    }
     741           2 :    while (groupLen > 0) {
     742           0 :       meta->pds2.sect2.unknown.dataLen += groupLen;
     743           0 :       meta->pds2.sect2.unknown.data = (double *)
     744           0 :             realloc ((void *) meta->pds2.sect2.unknown.data,
     745           0 :                      meta->pds2.sect2.unknown.dataLen * sizeof (double));
     746           0 :       for (j = 0; j < groupLen; j++) {
     747           0 :          meta->pds2.sect2.unknown.data[ansLoc++] = rdat[loc++];
     748             :       }
     749           0 :       if (nrdat <= loc) {
     750           0 :          groupLen = 0;
     751             :       } else {
     752           0 :          groupLen = (sInt4) rdat[loc++];
     753           0 :          if (groupLen != 0) {
     754           0 :             loc++;      /* Skip the decimal scale factor data. */
     755           0 :             if (nrdat <= loc + groupLen) {
     756           0 :                errSprintf ("ERROR: Ran out of rdat data\n");
     757           0 :                return -1;
     758             :             }
     759             :          }
     760             :       }
     761             :    }
     762             : 
     763             :    /* Work with idat data. */
     764           2 :    loc = 0;
     765           2 :    if (nidat <= loc) {
     766           0 :       errSprintf ("ERROR: Ran out of idat data\n");
     767           0 :       return -1;
     768             :    }
     769           2 :    groupLen = idat[loc++];
     770           2 :    loc++;               /* Skip the decimal scale factor data. */
     771           2 :    if (nidat <= loc + groupLen) {
     772           0 :       errSprintf ("ERROR: Ran out of idat data\n");
     773           0 :       return -1;
     774             :    }
     775           2 :    while (groupLen > 0) {
     776           0 :       meta->pds2.sect2.unknown.dataLen += groupLen;
     777           0 :       meta->pds2.sect2.unknown.data = (double *)
     778           0 :             realloc ((void *) meta->pds2.sect2.unknown.data,
     779           0 :                      meta->pds2.sect2.unknown.dataLen * sizeof (double));
     780           0 :       for (j = 0; j < groupLen; j++) {
     781           0 :          meta->pds2.sect2.unknown.data[ansLoc++] = idat[loc++];
     782             :       }
     783           0 :       if (nidat <= loc) {
     784           0 :          groupLen = 0;
     785             :       } else {
     786           0 :          groupLen = idat[loc++];
     787           0 :          if (groupLen != 0) {
     788           0 :             loc++;      /* Skip the decimal scale factor data. */
     789           0 :             if (nidat <= loc + groupLen) {
     790           0 :                errSprintf ("ERROR: Ran out of idat data\n");
     791           0 :                return -1;
     792             :             }
     793             :          }
     794             :       }
     795             :    }
     796           2 :    return 0;
     797             : }
     798             : 
     799             : /*****************************************************************************
     800             :  * ParseSect3() --
     801             :  *
     802             :  * Arthur Taylor / MDL
     803             :  *
     804             :  * PURPOSE
     805             :  *   To verify and parse section 3 data.
     806             :  *
     807             :  * ARGUMENTS
     808             :  *  is3 = The unpacked section 3 array. (Input)
     809             :  *  ns3 = The size of section 3. (Input)
     810             :  * meta = The structure to fill. (Output)
     811             :  *
     812             :  * FILES/DATABASES: None
     813             :  *
     814             :  * RETURNS: int (could use errSprintf())
     815             :  *  0 = OK
     816             :  * -1 = ns3 is too small.
     817             :  * -2 = unexpected values in is3.
     818             :  * -3 = un-supported map Projection.
     819             :  *
     820             :  * HISTORY
     821             :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
     822             :  *   9/2003 AAT: Adjusted Radius Earth case 1,6 to be based on:
     823             :  *          Y * 10^D = R
     824             :  *          Where Y = original value, D is scale factor, R is scale value.
     825             :  *   1/2004 AAT: Adjusted Radius Earth case 6 to always be 6371.229 km
     826             :  *
     827             :  * NOTES
     828             :  * Need to add support for GS3_ORTHOGRAPHIC = 90,
     829             :  *   GS3_EQUATOR_EQUIDIST = 110, GS3_AZIMUTH_RANGE = 120
     830             :  *****************************************************************************
     831             :  */
     832         457 : static int ParseSect3 (sInt4 *is3, sInt4 ns3, grib_MetaData *meta)
     833             : {
     834             :    double unit;         /* Used to convert from stored value to degrees
     835             :                          * lat/lon. See GRIB2 Regulation 92.1.6 */
     836             :    sInt4 angle;         /* For Lat/Lon, 92.1.6 may not hold, in which case,
     837             :                          * angle != 0, and unit = angle/subdivision. */
     838             :    sInt4 subdivision;   /* see angle explanation. */
     839         457 :    int ret = 0;
     840             : 
     841         457 :    if (ns3 < 14) {
     842           0 :       return -1;
     843             :    }
     844         457 :    if (is3[4] != 3) {
     845           0 :       errSprintf ("ERROR IS3 not labeled correctly. %ld\n", is3[4]);
     846           0 :       return -2;
     847             :    }
     848         457 :    if (is3[5] != 0) {
     849           0 :       errSprintf ("Can not handle 'Source of Grid Definition' = %ld\n",
     850           0 :                   is3[5]);
     851           0 :       errSprintf ("Can only handle grids defined in Code table 3.1\n");
     852             :       // return -3;
     853             :    }
     854         457 :    meta->gds.numPts = is3[6];
     855         457 :    if ((is3[10] != 0) || (is3[11] != 0)) {
     856           0 :       errSprintf ("Un-supported Map Projection.\n  All Supported "
     857             :                   "projections have 0 bytes following the template.\n");
     858             :       // return -3;
     859             :    }
     860         457 :    meta->gds.projType = (uChar) is3[12];
     861             : 
     862             :    // Do not refuse to convert the GRIB file if only the projection is unknown.
     863             : 
     864             :    /*
     865             :    if ((is3[12] != GS3_LATLON) && (is3[12] != GS3_MERCATOR) &&
     866             :        (is3[12] != GS3_POLAR) && (is3[12] != GS3_LAMBERT)) {
     867             :       errSprintf ("Un-supported Map Projection %ld\n", is3[12]);
     868             :       return -3;
     869             :    }
     870             :    */
     871             : 
     872             :    /*
     873             :     * Handle variables common to the supported templates.
     874             :     */
     875         457 :    if (ns3 < 38) {
     876           0 :       return -1;
     877             :    }
     878             :    /* Assert: is3[14] is the shape of the earth. */
     879         457 :    meta->gds.hdatum = 0;
     880         457 :    switch (is3[14]) {
     881           2 :       case 0:
     882           2 :          meta->gds.f_sphere = 1;
     883           2 :          meta->gds.majEarth = 6367.47;
     884           2 :          meta->gds.minEarth = 6367.47;
     885           2 :          break;
     886          13 :       case 6:
     887          13 :          meta->gds.f_sphere = 1;
     888          13 :          meta->gds.majEarth = 6371.229;
     889          13 :          meta->gds.minEarth = 6371.229;
     890          13 :          break;
     891         108 :       case 1:
     892         108 :          meta->gds.f_sphere = 1;
     893             :          /* Following assumes scale factor and scale value refer to
     894             :           * scientific notation. */
     895             :          /* Incorrect Assumption (9/8/2003): scale factor / value are based
     896             :           * on: Y * 10^D = R, where Y = original value, D = scale factor, ___
     897             :           * R = scale value. */
     898             : 
     899             :          // File of https://github.com/OSGeo/gdal/issues/7811
     900             :          // has is3[16] == -1 and is3[15] = 255
     901         108 :          if (is3[16] > 0 && is3[15] != 255 &&
     902         106 :              (is3[16] != GRIB2MISSING_s4) && (is3[15] != GRIB2MISSING_s1)) {
     903             :             /* Assumes data is given in m (not km). */
     904         106 :             double denom = pow (10.0, is3[15]) * 1000.;
     905         106 :             if( denom == 0 )
     906             :             {
     907           0 :                 errSprintf ("Invalid radius.\n");
     908           0 :                 ret = -2;
     909             :             }
     910             :             else
     911             :             {
     912         106 :                 meta->gds.majEarth = is3[16] / denom;
     913         106 :                 meta->gds.minEarth = meta->gds.majEarth;
     914         106 :             }
     915             :          } else {
     916           2 :             errSprintf ("Missing info on radius of Earth.\n");
     917           2 :             ret = -2;
     918             :          }
     919             :          /* Check if our m assumption was valid. If it was not, they give us
     920             :           * 6371 km, which we convert to 6.371 < 6.4 */
     921         108 :          if (ret == 0 && meta->gds.majEarth < 6.4) {
     922           0 :             meta->gds.majEarth = meta->gds.majEarth * 1000.;
     923           0 :             meta->gds.minEarth = meta->gds.minEarth * 1000.;
     924             :          }
     925         108 :          break;
     926           2 :       case 2:
     927           2 :          meta->gds.f_sphere = 0;
     928           2 :          meta->gds.majEarth = 6378.160;
     929           2 :          meta->gds.minEarth = 6356.775;
     930           2 :          break;
     931           2 :       case 4: // GRS80
     932           2 :          meta->gds.f_sphere = 0;
     933           2 :          meta->gds.majEarth = 6378.137;
     934           2 :          meta->gds.minEarth = meta->gds.majEarth * (1 - 1 / 298.257222101);
     935           2 :          break;
     936         134 :       case 5: // WGS84
     937         134 :          meta->gds.f_sphere = 0;
     938         134 :          meta->gds.majEarth = 6378.137;
     939         134 :          meta->gds.minEarth = meta->gds.majEarth * (1 - 1 / 298.257223563);
     940         134 :          break;
     941           0 :       case 3:
     942           0 :          meta->gds.f_sphere = 0;
     943             :          /* Following assumes scale factor and scale value refer to
     944             :           * scientific notation. */
     945             :          /* Incorrect Assumption (9/8/2003): scale factor / value are based
     946             :           * on: Y * 10^D = R, where Y = original value, D = scale factor, ___
     947             :           * R = scale value. */
     948           0 :          if ((is3[21] != GRIB2MISSING_s4) && (is3[20] != GRIB2MISSING_s1) &&
     949           0 :              (is3[26] != GRIB2MISSING_s4) && (is3[25] != GRIB2MISSING_s1)) {
     950             :             /* Assumes data is given in km (not m). */
     951           0 :             double denomMaj = pow (10.0, is3[20]);
     952           0 :             double denomMin = pow (10.0, is3[25]);
     953           0 :             if( denomMaj == 0.0 || denomMin == 0.0 )
     954             :             {
     955           0 :                 errSprintf ("Invalid major / minor axis.\n");
     956           0 :                 ret = -2;
     957             :             }
     958             :             else
     959             :             {
     960           0 :                 meta->gds.majEarth = is3[21] / denomMaj;
     961           0 :                 meta->gds.minEarth = is3[26] / denomMin;
     962           0 :             }
     963             :          } else {
     964           0 :             errSprintf ("Missing info on major / minor axis of Earth.\n");
     965           0 :             ret = -2;
     966             :          }
     967             :          /* Check if our km assumption was valid. If it was not, they give us
     968             :           * 6371000 m, which is > 6400. */
     969           0 :          if (meta->gds.majEarth > 6400) {
     970           0 :             meta->gds.majEarth = meta->gds.majEarth / 1000.;
     971             :          }
     972           0 :          if (meta->gds.minEarth > 6400) {
     973           0 :             meta->gds.minEarth = meta->gds.minEarth / 1000.;
     974             :          }
     975           0 :          break;
     976         196 :       case 7:
     977         196 :          meta->gds.f_sphere = 0;
     978             :          /* Following assumes scale factor and scale value refer to
     979             :           * scientific notation. */
     980             :          /* Incorrect Assumption (9/8/2003): scale factor / value are based
     981             :           * on: Y * 10^D = R, where Y = original value, D = scale factor, ___
     982             :           * R = scale value. */
     983         196 :          if ((is3[21] != GRIB2MISSING_s4) && (is3[20] != GRIB2MISSING_s1) &&
     984         196 :              (is3[26] != GRIB2MISSING_s4) && (is3[25] != GRIB2MISSING_s1)) {
     985             :             /* Assumes data is given in m (not km). */
     986         196 :             double denomMaj = pow (10.0, is3[20]) * 1000.;
     987         196 :             double denomMin = pow (10.0, is3[25]) * 1000.;
     988         196 :             if( denomMaj == 0.0 || denomMin == 0.0 )
     989             :             {
     990           0 :                 errSprintf ("Invalid major / minor axis.\n");
     991           0 :                 ret = -2;
     992             :             }
     993             :             else
     994             :             {
     995         196 :                 meta->gds.majEarth = is3[21] / denomMaj;
     996         196 :                 meta->gds.minEarth = is3[26] / denomMin;
     997         196 :             }
     998             :          } else {
     999           0 :             errSprintf ("Missing info on major / minor axis of Earth.\n");
    1000           0 :             ret = -2;
    1001             :          }
    1002             :          /* Check if our m assumption was valid. If it was not, they give us
    1003             :           * 6371 km, which we convert to 6.371 < 6.4 */
    1004         196 :          if (meta->gds.majEarth < 6.4) {
    1005           0 :             meta->gds.majEarth = meta->gds.majEarth * 1000.;
    1006             :          }
    1007         196 :          if (meta->gds.minEarth < 6.4) {
    1008           0 :             meta->gds.minEarth = meta->gds.minEarth * 1000.;
    1009             :          }
    1010         196 :          break;
    1011           0 :       case 8:
    1012           0 :          meta->gds.f_sphere = 1;
    1013           0 :          meta->gds.majEarth = 6371.2;
    1014           0 :          meta->gds.minEarth = 6371.2;
    1015           0 :          meta->gds.hdatum = 1;
    1016           0 :          break;
    1017           0 :       default:
    1018           0 :          errSprintf ("Undefined shape of earth? %ld\n", is3[14]);
    1019           0 :          return -2;
    1020             :    }
    1021             :    /* Validate the radEarth is reasonable. */
    1022         457 :    if ((meta->gds.majEarth > 6400) || (meta->gds.majEarth < 6300) ||
    1023         455 :        (meta->gds.minEarth > 6400) || (meta->gds.minEarth < 6300)) {
    1024           2 :       errSprintf ("Bad shape of earth? %f %f\n", meta->gds.majEarth,
    1025             :                   meta->gds.minEarth);
    1026           2 :       meta->gds.majEarth = -1;
    1027           2 :       meta->gds.minEarth = -1;
    1028           2 :       ret = -2;
    1029             :    }
    1030         457 :    meta->gds.Nx = is3[30];
    1031         457 :    meta->gds.Ny = is3[34];
    1032         457 :    if ((meta->gds.Nx != 0 && meta->gds.Ny > UINT_MAX / meta->gds.Nx) ||
    1033         457 :        meta->gds.Nx * meta->gds.Ny != meta->gds.numPts) {
    1034           0 :       errSprintf ("Nx * Ny != number of points?\n");
    1035           0 :       return -2;
    1036             :    }
    1037             : 
    1038             :    /* Initialize variables prior to parsing the specific templates. */
    1039         457 :    unit = 1e-6;
    1040         457 :    meta->gds.center = 0;
    1041         457 :    meta->gds.scaleLat1 = meta->gds.scaleLat2 = 0;
    1042         457 :    meta->gds.southLat = meta->gds.southLon = 0;
    1043         457 :    meta->gds.lat2 = meta->gds.lon2 = 0;
    1044         457 :    switch (is3[12]) {
    1045         186 :       case GS3_LATLON: /* 0: Regular lat/lon grid. */
    1046             :       case GS3_ROTATED_LATLON: // 1: Rotated lat/lon grid
    1047             :       case GS3_GAUSSIAN_LATLON:  /* 40: Gaussian lat/lon grid. */
    1048         186 :          if (ns3 < 72) {
    1049           0 :             return -1;
    1050             :          }
    1051         186 :          angle = is3[38];
    1052         186 :          subdivision = is3[42];
    1053         186 :          if (angle != 0) {
    1054           2 :             if (subdivision == 0) {
    1055           0 :                errSprintf ("subdivision of 0? Could not determine unit"
    1056             :                            " for latlon grid\n");
    1057           0 :                return -2;
    1058             :             }
    1059           2 :             unit = angle / (double) (subdivision);
    1060             :          }
    1061         186 :          if ((is3[46] == GRIB2MISSING_s4) || (is3[50] == GRIB2MISSING_s4) ||
    1062         186 :              (is3[55] == GRIB2MISSING_s4) || (is3[59] == GRIB2MISSING_s4) ||
    1063         186 :              (is3[63] == GRIB2MISSING_s4) || (is3[67] == GRIB2MISSING_s4)) {
    1064           0 :             errSprintf ("Lat/Lon grid is not defined completely.\n");
    1065           0 :             return -2;
    1066             :          }
    1067         186 :          meta->gds.lat1 = is3[46] * unit;
    1068         186 :          meta->gds.lon1 = is3[50] * unit;
    1069         186 :          meta->gds.resFlag = (uChar) is3[54];
    1070         186 :          meta->gds.lat2 = is3[55] * unit;
    1071         186 :          meta->gds.lon2 = is3[59] * unit;
    1072         186 :          meta->gds.Dx = is3[63] * unit; /* degrees. */
    1073         186 :          if (is3[12] == GS3_GAUSSIAN_LATLON) {
    1074           0 :             int np = is3[67]; /* parallels between a pole and the equator */
    1075           0 :             if( np == 0 )
    1076             :             {
    1077           0 :                 errSprintf ("Gaussian Lat/Lon grid is not defined completely.\n");
    1078           0 :                 return -2;
    1079             :             }
    1080           0 :             meta->gds.Dy = 90.0 / np;
    1081             :          } else
    1082         186 :             meta->gds.Dy = is3[67] * unit; /* degrees. */
    1083         186 :          meta->gds.scan = (uChar) is3[71];
    1084         186 :          meta->gds.meshLat = 0;
    1085         186 :          meta->gds.orientLon = 0;
    1086         186 :          if( is3[12] == GS3_ROTATED_LATLON ) {
    1087           1 :              if( ns3 < 84 ) {
    1088           0 :                  return -1;
    1089             :              }
    1090           1 :              meta->gds.f_typeLatLon = 3;
    1091           1 :              meta->gds.southLat = is3[73-1] * unit;
    1092           1 :              meta->gds.southLon = is3[77-1] * unit;
    1093           1 :              meta->gds.angleRotate = is3[81-1] * unit;
    1094             :          }
    1095             :          /* Resolve resolution flag(bit 3,4).  Copy Dx,Dy as appropriate. */
    1096         186 :          if ((meta->gds.resFlag & GRIB2BIT_3) &&
    1097         186 :              (!(meta->gds.resFlag & GRIB2BIT_4))) {
    1098           0 :             meta->gds.Dy = meta->gds.Dx;
    1099         186 :          } else if ((!(meta->gds.resFlag & GRIB2BIT_3)) &&
    1100           0 :                     (meta->gds.resFlag & GRIB2BIT_4)) {
    1101           0 :             meta->gds.Dx = meta->gds.Dy;
    1102             :          }
    1103         186 :          break;
    1104          43 :       case GS3_MERCATOR: /* 10: Mercator grid. */
    1105          43 :          if (ns3 < 72) {
    1106           0 :             return -1;
    1107             :          }
    1108          43 :          if ((is3[38] == GRIB2MISSING_s4) || (is3[42] == GRIB2MISSING_s4) ||
    1109          43 :              (is3[47] == GRIB2MISSING_s4) || (is3[51] == GRIB2MISSING_s4) ||
    1110          43 :              (is3[55] == GRIB2MISSING_s4) || (is3[60] == GRIB2MISSING_s4)) {
    1111           0 :             errSprintf ("Mercator grid is not defined completely.\n");
    1112           0 :             return -2;
    1113             :          }
    1114          43 :          meta->gds.lat1 = is3[38] * unit;
    1115          43 :          meta->gds.lon1 = is3[42] * unit;
    1116          43 :          meta->gds.resFlag = (uChar) is3[46];
    1117          43 :          meta->gds.meshLat = is3[47] * unit;
    1118          43 :          meta->gds.lat2 = is3[51] * unit;
    1119          43 :          meta->gds.lon2 = is3[55] * unit;
    1120          43 :          meta->gds.scan = (uChar) is3[59];
    1121          43 :          meta->gds.orientLon = is3[60] * unit;
    1122          43 :          meta->gds.Dx = is3[64] / 1000.; /* mm -> m */
    1123          43 :          meta->gds.Dy = is3[68] / 1000.; /* mm -> m */
    1124             :          /* Resolve resolution flag(bit 3,4).  Copy Dx,Dy as appropriate. */
    1125          43 :          if ((meta->gds.resFlag & GRIB2BIT_3) &&
    1126          21 :              (!(meta->gds.resFlag & GRIB2BIT_4))) {
    1127           0 :             if (is3[64] == GRIB2MISSING_s4) {
    1128           0 :                errSprintf ("Mercator grid is not defined completely.\n");
    1129           0 :                return -2;
    1130             :             }
    1131           0 :             meta->gds.Dy = meta->gds.Dx;
    1132          43 :          } else if ((!(meta->gds.resFlag & GRIB2BIT_3)) &&
    1133          22 :                     (meta->gds.resFlag & GRIB2BIT_4)) {
    1134           0 :             if (is3[68] == GRIB2MISSING_s4) {
    1135           0 :                errSprintf ("Mercator grid is not defined completely.\n");
    1136           0 :                return -2;
    1137             :             }
    1138           0 :             meta->gds.Dx = meta->gds.Dy;
    1139             :          }
    1140          43 :          break;
    1141         195 :       case GS3_TRANSVERSE_MERCATOR: /* 12: Transverse mercator */
    1142         195 :          if (ns3 < 84) {
    1143           0 :             return -1;
    1144             :          }
    1145         195 :          meta->gds.latitude_of_origin = is3[38] * unit;
    1146         195 :          meta->gds.central_meridian = is3[42] * unit;
    1147         195 :          meta->gds.resFlag = (uChar) is3[46];
    1148             :          {
    1149             :              float fTemp;
    1150         195 :              GUInt32 nTemp = is3[47] < 0 ? (-is3[47]) | 0x80000000U : is3[47];
    1151         195 :              memcpy(&fTemp, &nTemp, 4);
    1152         195 :              meta->gds.scaleLat1 = fTemp;
    1153             :          }
    1154         195 :          meta->gds.x0 = is3[51] / 100.0;
    1155         195 :          meta->gds.y0 = is3[55] / 100.0;
    1156         195 :          meta->gds.scan = (uChar) is3[59];
    1157         195 :          meta->gds.Dx = is3[60] / 100.0;
    1158         195 :          meta->gds.Dy = is3[64] / 100.0;
    1159         195 :          meta->gds.x1 = is3[68] / 100.0;
    1160         195 :          meta->gds.y1 = is3[72] / 100.0;
    1161         195 :          meta->gds.x2 = is3[76] / 100.0;
    1162         195 :          meta->gds.y2 = is3[80] / 100.0;
    1163         195 :          break;
    1164             : 
    1165          11 :       case GS3_POLAR:  /* 20: Polar Stereographic grid. */
    1166          11 :          if (ns3 < 65) {
    1167           0 :             return -1;
    1168             :          }
    1169          11 :          if ((is3[38] == GRIB2MISSING_s4) || (is3[42] == GRIB2MISSING_s4) ||
    1170          11 :              (is3[47] == GRIB2MISSING_s4) || (is3[51] == GRIB2MISSING_s4)) {
    1171           0 :             errSprintf ("Polar Stereographic grid is not defined "
    1172             :                         "completely.\n");
    1173           0 :             return -2;
    1174             :          }
    1175          11 :          meta->gds.lat1 = is3[38] * unit;
    1176          11 :          meta->gds.lon1 = is3[42] * unit;
    1177          11 :          meta->gds.resFlag = (uChar) is3[46];
    1178             :          /* Note (1) resFlag (bit 3,4) not applicable. */
    1179          11 :          meta->gds.meshLat = is3[47] * unit;
    1180          11 :          meta->gds.orientLon = is3[51] * unit;
    1181          11 :          meta->gds.Dx = is3[55] / 1000.; /* mm -> m */
    1182          11 :          meta->gds.Dy = is3[59] / 1000.; /* mm -> m */
    1183          11 :          meta->gds.center = (uChar) is3[63];
    1184          11 :          if (meta->gds.center & GRIB2BIT_1) {
    1185             :             /* South polar stereographic. */
    1186           0 :             meta->gds.scaleLat1 = meta->gds.scaleLat2 = -90;
    1187             :          } else {
    1188             :             /* North polar stereographic. */
    1189          11 :             meta->gds.scaleLat1 = meta->gds.scaleLat2 = 90;
    1190             :          }
    1191          11 :          if (meta->gds.center & GRIB2BIT_2) {
    1192           0 :             errSprintf ("Note (4) specifies no 'bi-polar stereograhic"
    1193             :                         " projections'.\n");
    1194           0 :             return -2;
    1195             :          }
    1196          11 :          meta->gds.scan = (uChar) is3[64];
    1197          11 :          break;
    1198          15 :       case GS3_LAMBERT: /* 30: Lambert Conformal grid. */
    1199             :       case GS3_ALBERS_EQUAL_AREA: /* 31: Albers equal area */
    1200          15 :          if (ns3 < 81) {
    1201           0 :             return -1;
    1202             :          }
    1203          15 :          if ((is3[38] == GRIB2MISSING_s4) || (is3[42] == GRIB2MISSING_s4) ||
    1204          15 :              (is3[47] == GRIB2MISSING_s4) || (is3[51] == GRIB2MISSING_s4) ||
    1205          15 :              (is3[65] == GRIB2MISSING_s4) || (is3[69] == GRIB2MISSING_s4)) {
    1206           0 :             if( is3[12] == GS3_LAMBERT )
    1207             :             {
    1208           0 :                 errSprintf ("Lambert Conformal grid is not defined "
    1209             :                             "completely.\n");
    1210             :             }
    1211             :             else
    1212             :             {
    1213           0 :                 errSprintf ("Albers Equal Area grid is not defined "
    1214             :                             "completely.\n");
    1215             :             }
    1216           0 :             return -2;
    1217             :          }
    1218          15 :          meta->gds.lat1 = is3[38] * unit;
    1219          15 :          meta->gds.lon1 = is3[42] * unit;
    1220          15 :          meta->gds.resFlag = (uChar) is3[46];
    1221             :          /* Note (3) resFlag (bit 3,4) not applicable. */
    1222          15 :          meta->gds.meshLat = is3[47] * unit;
    1223          15 :          meta->gds.orientLon = is3[51] * unit;
    1224          15 :          meta->gds.Dx = is3[55] / 1000.; /* mm -> m */
    1225          15 :          meta->gds.Dy = is3[59] / 1000.; /* mm -> m */
    1226          15 :          meta->gds.center = (uChar) is3[63];
    1227          15 :          meta->gds.scan = (uChar) is3[64];
    1228          15 :          meta->gds.scaleLat1 = is3[65] * unit;
    1229          15 :          meta->gds.scaleLat2 = is3[69] * unit;
    1230          15 :          if( (is3[73] == GRIB2MISSING_s4) || (is3[77] == GRIB2MISSING_s4) )
    1231             :          {
    1232          14 :              meta->gds.southLat = 0.0;
    1233          14 :              meta->gds.southLon = 0.0;
    1234             :          }
    1235             :          else
    1236             :          {
    1237           1 :             meta->gds.southLat = is3[73] * unit;
    1238           1 :             meta->gds.southLon = is3[77] * unit;
    1239             :          }
    1240          15 :          break;
    1241           0 :     case GS3_ORTHOGRAPHIC: /* 90: Orthographic grid. */
    1242             :          // Misusing gdsType elements (gdsType needs extension)
    1243           0 :          meta->gds.lat1 = is3[38];
    1244           0 :          meta->gds.lon1 = is3[42];
    1245           0 :          meta->gds.resFlag = (uChar) is3[46];
    1246           0 :          meta->gds.Dx = is3[47];
    1247           0 :          meta->gds.Dy = is3[51];
    1248             : 
    1249           0 :          meta->gds.lon2 = is3[55] / 1000.; /* xp - X-coordinateSub-satellite, mm -> m */
    1250           0 :          meta->gds.lat2 = is3[59] / 1000.; /* yp - Y-coordinateSub-satellite, mm -> m */
    1251           0 :          meta->gds.scan = (uChar) is3[63];
    1252           0 :          meta->gds.orientLon = is3[64]; /* angle */
    1253           0 :          meta->gds.stretchFactor = is3[68] * 1000000.; /* altitude */
    1254             : 
    1255           0 :          meta->gds.southLon = is3[72]; /* x0 - X-coordinateOrigin */
    1256           0 :          meta->gds.southLat = is3[76]; /* y0 - Y-coordinateOrigin */
    1257           0 :          break;
    1258           7 :     case GS3_LAMBERT_AZIMUTHAL: /* 140: Lambert Azimuthal Equal Area Projection */
    1259           7 :          meta->gds.lat1 = is3[38] * unit;
    1260           7 :          meta->gds.lon1 = is3[42] * unit;
    1261           7 :          meta->gds.meshLat = is3[46] * unit;
    1262           7 :          meta->gds.orientLon = is3[50] * unit;
    1263           7 :          meta->gds.resFlag = (uChar) is3[54];
    1264           7 :          meta->gds.Dx = is3[55] / 1000.; /* mm -> m */
    1265           7 :          meta->gds.Dy = is3[59] / 1000.; /* mm -> m */
    1266           7 :          meta->gds.scan = (uChar) is3[63];
    1267           7 :          break;
    1268           0 :       default:
    1269           0 :          errSprintf ("Un-supported Map Projection. %ld\n", is3[12]);
    1270             :          // Don't abandon the conversion only because of an unknown projection
    1271           0 :          break;
    1272             :          //return -3;
    1273             :    }
    1274         457 :    if (meta->gds.scan != GRIB2BIT_2) {
    1275             : #ifdef DEBUG
    1276           0 :       printf ("Scan mode is expected to be 0100 (i.e. %d) not %u\n",
    1277           0 :               GRIB2BIT_2, meta->gds.scan);
    1278           0 :       printf ("The merged GRIB2 Library should return it in 0100\n");
    1279           0 :       printf ("The merged library swaps both NCEP and MDL data to scan "
    1280             :               "mode 0100\n");
    1281             : #endif
    1282             : /*
    1283             :       errSprintf ("Scan mode is expected to be 0100 (i.e. %d) not %d",
    1284             :                   GRIB2BIT_2, meta->gds.scan);
    1285             :       return -2;
    1286             : */
    1287             :    }
    1288         457 :    return ret;
    1289             : }
    1290             : 
    1291             : /*****************************************************************************
    1292             :  * ParseSect4Time2secV1() --
    1293             :  *
    1294             :  * Arthur Taylor / MDL
    1295             :  *
    1296             :  * PURPOSE
    1297             :  *    Attempt to parse time data in units provided by GRIB1 table 4, to
    1298             :  * seconds.
    1299             :  *
    1300             :  * ARGUMENTS
    1301             :  * time = The delta time to convert. (Input)
    1302             :  * unit = The unit to convert. (Input)
    1303             :  *  ans = The converted answer. (Output)
    1304             :  *
    1305             :  * FILES/DATABASES: None
    1306             :  *
    1307             :  * RETURNS: int
    1308             :  *  0 = OK
    1309             :  * -1 = could not determine.
    1310             :  *
    1311             :  * HISTORY
    1312             :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
    1313             :  *   1/2005 AAT: Fixed unit2sec[] table to have element 10 be 10800 (3 hours)
    1314             :  *          instead of 0.
    1315             :  *
    1316             :  * NOTES
    1317             :  * http://www.nco.ncep.noaa.gov/pmb/docs/on388/table4.html
    1318             :  *****************************************************************************
    1319             :  */
    1320         289 : int ParseSect4Time2secV1 (sInt4 time, int unit, double *ans)
    1321             : {
    1322             :    /* Following is a lookup table for unit conversion (see code table 4.4). */
    1323             :    static const sInt4 unit2sec[] = {
    1324             :       60, 3600, 86400L, 0, 0,
    1325             :       0, 0, 0, 0, 0,
    1326             :       10800, 21600L, 43200L
    1327             :    };
    1328         289 :    if ((unit >= 0) && (unit < 13)) {
    1329         289 :       if (unit2sec[unit] != 0) {
    1330         289 :          *ans = (double) (time) * unit2sec[unit];
    1331         289 :          return 0;
    1332             :       }
    1333           0 :    } else if (unit == 254) {
    1334           0 :       *ans = (double) (time);
    1335           0 :       return 0;
    1336             :    }
    1337           0 :    *ans = 0;
    1338           0 :    return -1;
    1339             : }
    1340             : 
    1341             : /*****************************************************************************
    1342             :  * ParseSect4Time2sec() --
    1343             :  *
    1344             :  * Arthur Taylor / MDL
    1345             :  *
    1346             :  * PURPOSE
    1347             :  *    Attempt to parse time data in units provided by GRIB2 table 4.4, to
    1348             :  * seconds.
    1349             :  *
    1350             :  * ARGUMENTS
    1351             :  * refTime = To add "years / centuries / decades and normals", we need a
    1352             :  *           reference time.
    1353             :  *    delt = The delta time to convert. (Input)
    1354             :  *    unit = The unit to convert. (Input)
    1355             :  *     ans = The converted answer. (Output)
    1356             :  *
    1357             :  * FILES/DATABASES: None
    1358             :  *
    1359             :  * RETURNS: int
    1360             :  *  0 = OK
    1361             :  * -1 = could not determine.
    1362             :  *
    1363             :  * HISTORY
    1364             :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
    1365             :  *   1/2005 AAT: Fixed unit2sec[] table to have element 10 be 10800 (3 hours)
    1366             :  *          instead of 0.
    1367             :  *
    1368             :  * NOTES
    1369             :  *****************************************************************************
    1370             :  */
    1371         781 : int ParseSect4Time2sec (double refTime, sInt4 delt, int unit, double *ans)
    1372             : {
    1373             :    /* Following is a lookup table for unit conversion (see code table 4.4). */
    1374             :    static const sInt4 unit2sec[] = {
    1375             :       60, 3600, 86400L, 0, 0,
    1376             :       0, 0, 0, 0, 0,
    1377             :       10800, 21600L, 43200L, 1
    1378             :    };
    1379         781 :    if ((unit >= 0) && (unit < 14)) {
    1380         781 :       if (unit2sec[unit] != 0) {
    1381         781 :          *ans = (double) (delt) * unit2sec[unit];
    1382         781 :          return 0;
    1383             :       } else {
    1384             :          /* The procedure returns number of seconds to adjust by, rather
    1385             :           * than the new time, which is why we subtract refTime */
    1386           0 :          switch (unit) {
    1387           0 :             case 3: /* month */
    1388           0 :                *ans = Clock_AddMonthYear (refTime, delt, 0) - refTime;
    1389           0 :                return 0;
    1390           0 :             case 4: /* year */
    1391           0 :                *ans = Clock_AddMonthYear (refTime, 0, delt) - refTime;
    1392           0 :                return 0;
    1393           0 :             case 5: /* decade */
    1394           0 :                if( delt < INT_MIN / 10 || delt > INT_MAX / 10 )
    1395           0 :                    return -1;
    1396           0 :                *ans = Clock_AddMonthYear (refTime, 0, delt * 10) - refTime;
    1397           0 :                return 0;
    1398           0 :             case 6: /* normal (30 year) */
    1399           0 :                if( delt < INT_MIN / 30 || delt > INT_MAX / 30 )
    1400           0 :                    return -1;
    1401           0 :                *ans = Clock_AddMonthYear (refTime, 0, delt * 30) - refTime;
    1402           0 :                return 0;
    1403           0 :             case 7: /* century (100 year) */
    1404           0 :                if( delt < INT_MIN / 100 || delt > INT_MAX / 100 )
    1405           0 :                    return -1;
    1406           0 :                *ans = Clock_AddMonthYear (refTime, 0, delt * 100) - refTime;
    1407           0 :                return 0;
    1408             :          }
    1409             :       }
    1410             :    }
    1411           0 :    *ans = 0;
    1412           0 :    return -1;
    1413             : }
    1414             : 
    1415             : /*****************************************************************************
    1416             :  * sbit_2Comp_fourByte() -- Arthur Taylor / MDL
    1417             :  *
    1418             :  * PURPOSE
    1419             :  *    The NCEP g2clib-1.0.2 library stored the lower limits and upper limits
    1420             :  * of probabilities using unsigned ints, whereas version 1.0.4 used signed
    1421             :  * ints.  The reason for the change is because some thresholds were negative.
    1422             :  *    To encode a negative value using an unsigned int, 1.0.2 used "2's
    1423             :  * complement + 1".  To encode a negative value using signed an int, 1.0.4
    1424             :  * used a "sign bit".  Example -2 => FFFFFFFE (1.0.2) => 80000002 (1.0.4).
    1425             :  * The problem (for backward compatibility sake) is to be able to read both
    1426             :  * encodings and get -2.  If one only read the new encoding method, then
    1427             :  * archived data would not be handled.
    1428             :  *    The algorithm is: If the number is positive or missing, leave it alone.
    1429             :  * If the number is negative, look at the 2's complement method, and the sign
    1430             :  * bit method, and use the method which results in a smaller absolute value.
    1431             :  *
    1432             :  * ARGUMENTS
    1433             :  * data = The number read by NCEP's library. (Input)
    1434             :  *
    1435             :  * RETURNS: sInt4
    1436             :  *    The value of treating the number as read by either method
    1437             :  *
    1438             :  * HISTORY
    1439             :  * 10/2007 Arthur Taylor (MDL): Created.
    1440             :  *
    1441             :  * NOTES
    1442             :  * 1) This algorithm will impact the possible range of values, by reducing it
    1443             :  *    from -2^31..(2^31-1) to -2^30..(2^31-1).
    1444             :  * 2) The NCEP change also impacted large positive values.  One originally
    1445             :  *    could encode 0..2^32-1.  Some confusion could arrise if the value was
    1446             :  *    originally encoded by 1.0.2 was in the range of 2^31..2^32-1.
    1447             :  ****************************************************************************/
    1448           0 : sInt4 sbit_2Comp_fourByte(sInt4 data)
    1449             : {
    1450             :    sInt4 x;             /* The pos. 2's complement interpretation of data */
    1451             :    sInt4 y;             /* The pos. sign bit interpretation of data */
    1452             : 
    1453           0 :    if ((data == GRIB2MISSING_s4) || (data >= 0)) {
    1454           0 :       return data;
    1455             :    }
    1456           0 :    if( data == INT_MIN ) // doesn't make sense since it is negative 0 in sign bit logic
    1457           0 :       return 0;
    1458           0 :    x = ~data + 1;
    1459           0 :    y = data & 0x7fffffff;
    1460           0 :    if (x < y) {
    1461           0 :       return -1 * x;
    1462             :    } else {
    1463           0 :       return -1 * y;
    1464             :    }
    1465             : }
    1466             : 
    1467             : /*****************************************************************************
    1468             :  * sbit_2Comp_oneByte() -- Arthur Taylor / MDL
    1469             :  *
    1470             :  * PURPOSE
    1471             :  *    The NCEP g2clib-1.0.2 library stored the lower limits and upper limits
    1472             :  * of probabilities using unsigned ints, whereas version 1.0.4 used signed
    1473             :  * ints.  The reason for the change is because some thresholds were negative.
    1474             :  *    To encode a negative value using an unsigned int, 1.0.2 used "2's
    1475             :  * complement + 1".  To encode a negative value using signed an int, 1.0.4
    1476             :  * used a "sign bit".  Example -2 => 11111110 (1.0.2) => 10000010 (1.0.4).
    1477             :  * The problem (for backward compatibility sake) is to be able to read both
    1478             :  * encodings and get -2.  If one only read the new encoding method, then
    1479             :  * archived data would not be handled.
    1480             :  *    The algorithm is: If the number is positive or missing, leave it alone.
    1481             :  * If the number is negative, look at the 2's complement method, and the sign
    1482             :  * bit method, and use the method which results in a smaller absolute value.
    1483             :  *
    1484             :  * ARGUMENTS
    1485             :  * data = The number read by NCEP's library. (Input)
    1486             :  *
    1487             :  * RETURNS: sChar
    1488             :  *    The value of treating the number as read by either method
    1489             :  *
    1490             :  * HISTORY
    1491             :  * 10/2007 Arthur Taylor (MDL): Created.
    1492             :  *
    1493             :  * NOTES
    1494             :  * 1) This algorithm will impact the possible range of values, by reducing it
    1495             :  *    from -128..127 to -64...127.
    1496             :  * 2) The NCEP change also impacted large positive values.  One originally
    1497             :  *    could encode 0..255.  Some confusion could arrise if the value was
    1498             :  *    originally encoded by 1.0.2 was in the range of 128..255.
    1499             :  ****************************************************************************/
    1500           0 : sChar sbit_2Comp_oneByte(sChar data)
    1501             : {
    1502             :    sChar x;             /* The pos. 2's complement interpretation of data */
    1503             :    sChar y;             /* The pos. sign bit interpretation of data */
    1504             : 
    1505           0 :    if ((data == GRIB2MISSING_s1) || (data >= 0)) {
    1506           0 :       return data;
    1507             :    }
    1508           0 :    x = ~data + 1;
    1509           0 :    y = data & 0x7f;
    1510           0 :    if (x < y) {
    1511           0 :       return -1 * x;
    1512             :    } else {
    1513           0 :       return -1 * y;
    1514             :    }
    1515             : }
    1516             : 
    1517             : /*****************************************************************************
    1518             :  * ParseSect4() --
    1519             :  *
    1520             :  * Arthur Taylor / MDL
    1521             :  *
    1522             :  * PURPOSE
    1523             :  *   To verify and parse section 4 data.
    1524             :  *
    1525             :  * ARGUMENTS
    1526             :  *  is4 = The unpacked section 4 array. (Input)
    1527             :  *  ns4 = The size of section 4. (Input)
    1528             :  * meta = The structure to fill. (Output)
    1529             :  *
    1530             :  * FILES/DATABASES: None
    1531             :  *
    1532             :  * RETURNS: int (could use errSprintf())
    1533             :  *  0 = OK
    1534             :  * -1 = ns4 is too small.
    1535             :  * -2 = unexpected values in is4.
    1536             :  * -4 = un-supported Sect 4 template.
    1537             :  * -5 = unsupported forecast time unit.
    1538             :  * -6 = Ran out of memory.
    1539             :  *
    1540             :  * HISTORY
    1541             :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
    1542             :  *   3/2003 AAT: Added support for GS4_SATELLITE.
    1543             :  *   3/2003 AAT: Adjusted allocing of sect4.Interval (should be safer now).
    1544             :  *   9/2003 AAT: Adjusted interpretation of scale factor / value.
    1545             :  *   5/2004 AAT: Added some memory checks.
    1546             :  *   3/2005 AAT: Added a cast to (uChar) when comparing to GRIB2MISSING_1
    1547             :  *   3/2005 AAT: Added GS4_PROBABIL_PNT.
    1548             :  *
    1549             :  * NOTES
    1550             :  * Need to add support for GS4_RADAR = 20
    1551             :  *****************************************************************************
    1552             :  */
    1553         457 : static int ParseSect4 (sInt4 *is4, sInt4 ns4, grib_MetaData *meta)
    1554             : {
    1555             :    int i;               /* Counter for time intervals in template 4.8, 4.9
    1556             :                          * (typically 1) or counter for satellite band in
    1557             :                          * template 4.30. */
    1558             :    void *temp_ptr;      /* A temporary pointer when reallocating memory. */
    1559             :    char *msg;           /* A pointer to the current error message. */
    1560             : 
    1561         457 :    if (ns4 < 9) {
    1562           0 :       return -1;
    1563             :    }
    1564         457 :    if (is4[4] != 4) {
    1565             : #ifdef DEBUG
    1566           0 :       printf ("ERROR IS4 not labeled correctly. %d\n", is4[4]);
    1567             : #endif
    1568           0 :       errSprintf ("ERROR IS4 not labeled correctly. %d\n", is4[4]);
    1569           0 :       return -2;
    1570             :    }
    1571             : 
    1572         457 :    if ((is4[7] != GS4_ANALYSIS) && (is4[7] != GS4_ENSEMBLE) &&
    1573          74 :        (is4[7] != GS4_DERIVED) && (is4[7] != GS4_PROBABIL_PNT) &&
    1574          74 :        (is4[7] != GS4_PERCENT_PNT) && (is4[7] != GS4_ERROR) &&
    1575          74 :        (is4[7] != GS4_STATISTIC) && (is4[7] != GS4_PROBABIL_TIME) &&
    1576          29 :        (is4[7] != GS4_PERCENT_TIME) && (is4[7] != GS4_ENSEMBLE_STAT) &&
    1577          29 :        (is4[7] != GS4_SATELLITE) && (is4[7] != GS4_SATELLITE_SYNTHETIC) &&
    1578          21 :        (is4[7] != GS4_DERIVED_INTERVAL) && (is4[7] != GS4_STATISTIC_SPATIAL_AREA) &&
    1579          15 :        (is4[7] != GS4_ANALYSIS_CHEMICAL) && (is4[7] != GS4_OPTICAL_PROPERTIES_AEROSOL)) {
    1580             : #ifdef DEBUG
    1581             :       //printf ("Un-supported Template. %d\n", is4[7]);
    1582             : #endif
    1583           5 :       errSprintf ("Un-supported Template. %d\n", is4[7]);
    1584           5 :       return -4;
    1585             :    }
    1586         452 :    meta->pds2.sect4.templat = (unsigned short int) is4[7];
    1587             : 
    1588             :    /*
    1589             :     * Handle variables common to the supported templates.
    1590             :     */
    1591         452 :    if (ns4 < 34) {
    1592           0 :       return -1;
    1593             :    }
    1594         452 :    meta->pds2.sect4.cat = (uChar) is4[9];
    1595         452 :    meta->pds2.sect4.subcat = (uChar) is4[10];
    1596         452 :    int nOffset = 0;
    1597         452 :    if( is4[7] == GS4_ANALYSIS_CHEMICAL ) {
    1598           9 :         nOffset = 16 - 14;
    1599             :    }
    1600         443 :    else if( is4[7] == GS4_OPTICAL_PROPERTIES_AEROSOL ) {
    1601           1 :         nOffset = 38 - 14;
    1602             :    }
    1603         452 :    if (ns4 < 34 + nOffset) {
    1604           0 :       return -1;
    1605             :    }
    1606         452 :    meta->pds2.sect4.genProcess = (uChar) is4[11 + nOffset];
    1607             : 
    1608             :    /* Initialize variables prior to parsing the specific templates. */
    1609         452 :    meta->pds2.sect4.typeEnsemble = 0;
    1610         452 :    meta->pds2.sect4.perturbNum = 0;
    1611         452 :    meta->pds2.sect4.numberFcsts = 0;
    1612         452 :    meta->pds2.sect4.derivedFcst = (uChar)-1;
    1613         452 :    meta->pds2.sect4.validTime = meta->pds2.refTime;
    1614             : 
    1615         452 :    if (meta->pds2.sect4.templat == GS4_SATELLITE) {
    1616           0 :       meta->pds2.sect4.genID = (uChar) is4[12];
    1617           0 :       meta->pds2.sect4.numBands = (uChar) is4[13];
    1618           0 :       meta->pds2.sect4.bands =
    1619           0 :             (sect4_BandType *) realloc ((void *) meta->pds2.sect4.bands,
    1620           0 :                                         meta->pds2.sect4.numBands *
    1621             :                                         sizeof (sect4_BandType));
    1622           0 :       for (i = 0; i < meta->pds2.sect4.numBands; i++) {
    1623           0 :          if (ns4 < 20 + 10 * i + 1) {
    1624           0 :              return -1;
    1625             :          }
    1626           0 :          meta->pds2.sect4.bands[i].series =
    1627           0 :                (unsigned short int) is4[14 + 10 * i];
    1628           0 :          meta->pds2.sect4.bands[i].numbers =
    1629           0 :                (unsigned short int) is4[16 + 10 * i];
    1630           0 :          meta->pds2.sect4.bands[i].instType = (uChar) is4[18 + 10 * i];
    1631           0 :          meta->pds2.sect4.bands[i].centWaveNum.factor =
    1632           0 :                (uChar) is4[19 + 10 * i];
    1633           0 :          meta->pds2.sect4.bands[i].centWaveNum.value = is4[20 + 10 * i];
    1634             :       }
    1635             : 
    1636           0 :       meta->pds2.sect4.fstSurfType = GRIB2MISSING_u1;
    1637           0 :       meta->pds2.sect4.fstSurfScale = GRIB2MISSING_s1;
    1638           0 :       meta->pds2.sect4.fstSurfValue = 0;
    1639           0 :       meta->pds2.sect4.sndSurfType = GRIB2MISSING_u1;
    1640           0 :       meta->pds2.sect4.sndSurfScale = GRIB2MISSING_s1;
    1641           0 :       meta->pds2.sect4.sndSurfValue = 0;
    1642             : 
    1643           0 :       return 0;
    1644             :    }
    1645         452 :    if (meta->pds2.sect4.templat == GS4_SATELLITE_SYNTHETIC) {
    1646           8 :       meta->pds2.sect4.genID = (uChar) is4[12];
    1647           8 :       meta->pds2.sect4.numBands = (uChar) is4[22];
    1648           8 :       meta->pds2.sect4.bands =
    1649           8 :             (sect4_BandType *) realloc ((void *) meta->pds2.sect4.bands,
    1650           8 :                                         meta->pds2.sect4.numBands *
    1651             :                                         sizeof (sect4_BandType));
    1652          22 :       for (i = 0; i < meta->pds2.sect4.numBands; i++) {
    1653          14 :          if (ns4 < 30 + 11 * i + 1) {
    1654           0 :              return -1;
    1655             :          }
    1656          14 :          meta->pds2.sect4.bands[i].series =
    1657          14 :                (unsigned short int) is4[23 + 11 * i];
    1658          14 :          meta->pds2.sect4.bands[i].numbers =
    1659          14 :                (unsigned short int) is4[25 + 11 * i];
    1660          14 :          meta->pds2.sect4.bands[i].instType = (uChar) is4[27 + 11 * i];
    1661          14 :          meta->pds2.sect4.bands[i].centWaveNum.factor =
    1662          14 :                (uChar) is4[29 + 11 * i];
    1663          14 :          meta->pds2.sect4.bands[i].centWaveNum.value = is4[30 + 11 * i];
    1664             :       }
    1665             : 
    1666           8 :       meta->pds2.sect4.fstSurfType = GRIB2MISSING_u1;
    1667           8 :       meta->pds2.sect4.fstSurfScale = GRIB2MISSING_s1;
    1668           8 :       meta->pds2.sect4.fstSurfValue = 0;
    1669           8 :       meta->pds2.sect4.sndSurfType = GRIB2MISSING_u1;
    1670           8 :       meta->pds2.sect4.sndSurfScale = GRIB2MISSING_s1;
    1671           8 :       meta->pds2.sect4.sndSurfValue = 0;
    1672             : 
    1673           8 :       return 0;
    1674             :    }
    1675             : 
    1676         444 :    meta->pds2.sect4.bgGenID = (uChar) is4[12 + nOffset];
    1677         444 :    meta->pds2.sect4.genID = (uChar) is4[13 + nOffset];
    1678         444 :    if ((is4[14 + nOffset] == GRIB2MISSING_u2) || (is4[16 + nOffset] == GRIB2MISSING_u1)) {
    1679          47 :       meta->pds2.sect4.f_validCutOff = 0;
    1680          47 :       meta->pds2.sect4.cutOff = 0;
    1681             :    } else {
    1682         397 :       meta->pds2.sect4.f_validCutOff = 1;
    1683         397 :       meta->pds2.sect4.cutOff = is4[14 + nOffset] * 3600 + is4[16 + nOffset] * 60;
    1684             :    }
    1685             : /*   if (is4[18] == GRIB2MISSING_s4) */
    1686         444 :    if (is4[18] < -1 * (0x3fffffff)) {
    1687             :       //printf ("  Warning - Forecast time %ld is 'too' negative.\n", is4[18]);
    1688             :       //printf ("  Assuming incorrect decoding of 2s complement.");
    1689           0 :       is4[18] = -1 * (int)(((unsigned)is4[18])^(0x80000000));
    1690             :       //printf ("  Using %ld\n", is4[18]);
    1691             :    }
    1692             : 
    1693         444 :    meta->pds2.sect4.foreUnit = is4[17 + nOffset];
    1694         444 :    if (ParseSect4Time2sec (meta->pds2.refTime, is4[18 + nOffset], is4[17 + nOffset],
    1695         444 :                            &(meta->pds2.sect4.foreSec)) != 0) {
    1696           0 :       errSprintf ("Unable to convert this TimeUnit: %ld\n", is4[17 + nOffset]);
    1697           0 :       return -5;
    1698             :    }
    1699             : 
    1700         444 :    meta->pds2.sect4.validTime = (time_t) (meta->pds2.refTime +
    1701         444 :                                           meta->pds2.sect4.foreSec);
    1702             : 
    1703             :    /*
    1704             :     * Following is based on what was needed to get correct Radius of Earth in
    1705             :     * section 3.  (Hopefully they are consistent).
    1706             :     */
    1707         444 :    meta->pds2.sect4.fstSurfType = (uChar) is4[22 + nOffset];
    1708         444 :    if ((is4[24 + nOffset] == GRIB2MISSING_s4) || (is4[23 + nOffset] == GRIB2MISSING_s1) ||
    1709         431 :        (meta->pds2.sect4.fstSurfType == GRIB2MISSING_u1)) {
    1710          13 :       meta->pds2.sect4.fstSurfScale = GRIB2MISSING_s1;
    1711          13 :       meta->pds2.sect4.fstSurfValue = 0;
    1712             :    } else {
    1713         431 :       meta->pds2.sect4.fstSurfScale = is4[23 + nOffset];
    1714         431 :       meta->pds2.sect4.fstSurfValue = is4[24 + nOffset] / pow (10.0, is4[23 + nOffset]);
    1715             :    }
    1716         444 :    meta->pds2.sect4.sndSurfType = (uChar) is4[28 + nOffset];
    1717         444 :    if ((is4[30 + nOffset] == GRIB2MISSING_s4) || (is4[29 + nOffset] == GRIB2MISSING_s1) ||
    1718          93 :        (meta->pds2.sect4.sndSurfType == GRIB2MISSING_u1)) {
    1719         444 :       meta->pds2.sect4.sndSurfScale = GRIB2MISSING_s1;
    1720         444 :       meta->pds2.sect4.sndSurfValue = 0;
    1721             :    } else {
    1722           0 :       meta->pds2.sect4.sndSurfScale = is4[29 + nOffset];
    1723           0 :       meta->pds2.sect4.sndSurfValue = is4[30 + nOffset] / pow (10.0, is4[29 + nOffset]);
    1724             :    }
    1725         444 :    switch (meta->pds2.sect4.templat) {
    1726         383 :       case GS4_ANALYSIS: /* 4.0 */
    1727             :       case GS4_ERROR: /* 4.7 */
    1728         383 :          break;
    1729           0 :       case GS4_ENSEMBLE: /* 4.1 */
    1730           0 :          if (ns4 < 37) {
    1731           0 :             return -1;
    1732             :          }
    1733           0 :          meta->pds2.sect4.typeEnsemble = (uChar) is4[34];
    1734           0 :          meta->pds2.sect4.perturbNum = (uChar) is4[35];
    1735           0 :          meta->pds2.sect4.numberFcsts = (uChar) is4[36];
    1736           0 :          break;
    1737           0 :       case GS4_ENSEMBLE_STAT: /* 4.11 */
    1738           0 :          if (ns4 < 46) {
    1739           0 :             return -1;
    1740             :          }
    1741           0 :          meta->pds2.sect4.typeEnsemble = (uChar) is4[34];
    1742           0 :          meta->pds2.sect4.perturbNum = (uChar) is4[35];
    1743           0 :          meta->pds2.sect4.numberFcsts = (uChar) is4[36];
    1744           0 :          if (ParseTime (&(meta->pds2.sect4.validTime), is4[37], is4[39],
    1745           0 :                         is4[40], is4[41], is4[42], is4[43]) != 0) {
    1746           0 :             msg = errSprintf (nullptr);
    1747           0 :             meta->pds2.sect4.numInterval = (uChar) is4[44];
    1748           0 :             if (meta->pds2.sect4.numInterval != 1) {
    1749           0 :                errSprintf ("ERROR: in call to ParseTime from ParseSect4\n%s",
    1750             :                            msg);
    1751           0 :                errSprintf ("Most likely they didn't complete bytes 38-44 of "
    1752             :                            "Template 4.11\n");
    1753           0 :                free (msg);
    1754           0 :                meta->pds2.sect4.numInterval = 0;
    1755           0 :                return -1;
    1756             :             }
    1757           0 :             printf ("Warning: in call to ParseTime from ParseSect4\n%s", msg);
    1758           0 :             free (msg);
    1759           0 :             meta->pds2.sect4.validTime = (time_t) (meta->pds2.refTime +
    1760           0 :                                                    meta->pds2.sect4.foreSec);
    1761           0 :             printf ("Most likely they didn't complete bytes 38-44 of "
    1762             :                     "Template 4.11\n");
    1763             :          } else {
    1764           0 :             meta->pds2.sect4.numInterval = (uChar) is4[44];
    1765             :          }
    1766             : 
    1767             :          /* Added this check because some MOS grids didn't finish the
    1768             :           * template. */
    1769           0 :          if (meta->pds2.sect4.numInterval != 0) {
    1770           0 :             temp_ptr = realloc ((void *) meta->pds2.sect4.Interval,
    1771           0 :                                 meta->pds2.sect4.numInterval *
    1772             :                                 sizeof (sect4_IntervalType));
    1773           0 :             if (temp_ptr == nullptr) {
    1774           0 :                printf ("Ran out of memory.\n");
    1775           0 :                return -6;
    1776             :             }
    1777           0 :             meta->pds2.sect4.Interval = (sect4_IntervalType *) temp_ptr;
    1778           0 :             meta->pds2.sect4.numMissing = is4[45];
    1779           0 :             if (ns4 < 57 + (meta->pds2.sect4.numInterval-1)*12+1) {
    1780           0 :                 return -1;
    1781             :             }
    1782           0 :             for (i = 0; i < meta->pds2.sect4.numInterval; i++) {
    1783           0 :                meta->pds2.sect4.Interval[i].processID =
    1784           0 :                      (uChar) is4[49 + i * 12];
    1785           0 :                meta->pds2.sect4.Interval[i].incrType =
    1786           0 :                      (uChar) is4[50 + i * 12];
    1787           0 :                meta->pds2.sect4.Interval[i].timeRangeUnit =
    1788           0 :                      (uChar) is4[51 + i * 12];
    1789           0 :                meta->pds2.sect4.Interval[i].lenTime = is4[52 + i * 12];
    1790           0 :                meta->pds2.sect4.Interval[i].incrUnit =
    1791           0 :                      (uChar) is4[56 + i * 12];
    1792           0 :                meta->pds2.sect4.Interval[i].timeIncr =
    1793           0 :                      (uChar) is4[57 + i * 12];
    1794             :             }
    1795             :          } else {
    1796             : #ifdef DEBUG
    1797           0 :             printf ("Caution: Template 4.11 had no Intervals.\n");
    1798             : #endif
    1799           0 :             meta->pds2.sect4.numMissing = is4[45];
    1800             :          }
    1801           0 :          break;
    1802           0 :       case GS4_DERIVED: /* 4.2 */
    1803           0 :          if (ns4 < 36) {
    1804           0 :             return -1;
    1805             :          }
    1806           0 :          meta->pds2.sect4.derivedFcst = (uChar) is4[34];
    1807           0 :          meta->pds2.sect4.numberFcsts = (uChar) is4[35];
    1808           0 :          break;
    1809           0 :       case GS4_DERIVED_CLUSTER_RECTANGULAR_AREA: /* 4.3 */
    1810           0 :          if (ns4 < 68) {
    1811           0 :             return -1;
    1812             :          }
    1813           0 :          meta->pds2.sect4.derivedFcst = (uChar) is4[34];
    1814           0 :          meta->pds2.sect4.numberFcsts = (uChar) is4[35];
    1815           0 :          break;
    1816           0 :       case GS4_DERIVED_CLUSTER_CIRCULAR_AREA: /* 4.4 */
    1817           0 :          if (ns4 < 64) {
    1818           0 :             return -1;
    1819             :          }
    1820           0 :          meta->pds2.sect4.derivedFcst = (uChar) is4[34];
    1821           0 :          meta->pds2.sect4.numberFcsts = (uChar) is4[35];
    1822           0 :          break;
    1823           4 :       case GS4_DERIVED_INTERVAL: /* 4.12 */
    1824           4 :          if (ns4 < 45) {
    1825           0 :             return -1;
    1826             :          }
    1827           4 :          meta->pds2.sect4.derivedFcst = (uChar) is4[34];
    1828           4 :          meta->pds2.sect4.numberFcsts = (uChar) is4[35];
    1829             : 
    1830           8 :          if (ParseTime (&(meta->pds2.sect4.validTime), is4[36], is4[38],
    1831           4 :                         is4[39], is4[40], is4[41], is4[42]) != 0) {
    1832           0 :             msg = errSprintf (nullptr);
    1833           0 :             meta->pds2.sect4.numInterval = (uChar) is4[43];
    1834           0 :             if (meta->pds2.sect4.numInterval != 1) {
    1835           0 :                errSprintf ("ERROR: in call to ParseTime from ParseSect4\n%s",
    1836             :                            msg);
    1837           0 :                errSprintf ("Most likely they didn't complete bytes 37-43 of "
    1838             :                            "Template 4.12\n");
    1839           0 :                free (msg);
    1840           0 :                meta->pds2.sect4.numInterval = 0;
    1841           0 :                return -1;
    1842             :             }
    1843           0 :             printf ("Warning: in call to ParseTime from ParseSect4\n%s", msg);
    1844           0 :             free (msg);
    1845           0 :             meta->pds2.sect4.validTime = (time_t) (meta->pds2.refTime +
    1846           0 :                                                    meta->pds2.sect4.foreSec);
    1847           0 :             printf ("Most likely they didn't complete bytes 37-43 of "
    1848             :                     "Template 4.12\n");
    1849             :          } else {
    1850           4 :             meta->pds2.sect4.numInterval = (uChar) is4[43];
    1851             :          }
    1852             : 
    1853             :          /* Added this check because some MOS grids didn't finish the
    1854             :           * template. */
    1855           4 :          if (meta->pds2.sect4.numInterval != 0) {
    1856           4 :             temp_ptr = realloc ((void *) meta->pds2.sect4.Interval,
    1857           4 :                                 meta->pds2.sect4.numInterval *
    1858             :                                 sizeof (sect4_IntervalType));
    1859           4 :             if (temp_ptr == nullptr) {
    1860           0 :                printf ("Ran out of memory.\n");
    1861           0 :                return -6;
    1862             :             }
    1863           4 :             meta->pds2.sect4.Interval = (sect4_IntervalType *) temp_ptr;
    1864           4 :             meta->pds2.sect4.numMissing = is4[44];
    1865           4 :             if (ns4 < 56 + (meta->pds2.sect4.numInterval-1)*12+1) {
    1866           0 :                 return -1;
    1867             :             }
    1868           8 :             for (i = 0; i < meta->pds2.sect4.numInterval; i++) {
    1869           4 :                meta->pds2.sect4.Interval[i].processID =
    1870           4 :                      (uChar) is4[48 + i * 12];
    1871           4 :                meta->pds2.sect4.Interval[i].incrType =
    1872           4 :                      (uChar) is4[49 + i * 12];
    1873           4 :                meta->pds2.sect4.Interval[i].timeRangeUnit =
    1874           4 :                      (uChar) is4[50 + i * 12];
    1875           4 :                meta->pds2.sect4.Interval[i].lenTime = is4[51 + i * 12];
    1876           4 :                meta->pds2.sect4.Interval[i].incrUnit =
    1877           4 :                      (uChar) is4[55 + i * 12];
    1878           4 :                meta->pds2.sect4.Interval[i].timeIncr =
    1879           4 :                      (uChar) is4[56 + i * 12];
    1880             :             }
    1881             :          } else {
    1882             : #ifdef DEBUG
    1883           0 :             printf ("Caution: Template 4.12 had no Intervals.\n");
    1884             : #endif
    1885           0 :             meta->pds2.sect4.numMissing = is4[44];
    1886             :          }
    1887           4 :          break;
    1888           0 :       case GS4_DERIVED_INTERVAL_CLUSTER_RECTANGULAR_AREA: /* 4.13 */
    1889             :       case GS4_DERIVED_INTERVAL_CLUSTER_CIRCULAR_AREA: /* 4.14 */
    1890           0 :          if (ns4 < 36) {
    1891           0 :             return -1;
    1892             :          }
    1893           0 :          meta->pds2.sect4.derivedFcst = (uChar) is4[34];
    1894           0 :          meta->pds2.sect4.numberFcsts = (uChar) is4[35];
    1895           0 :          break;
    1896          45 :       case GS4_STATISTIC: /* 4.8 */
    1897          45 :          if (ns4 < 43) {
    1898           0 :             return -1;
    1899             :          }
    1900          90 :          if (ParseTime (&(meta->pds2.sect4.validTime), is4[34], is4[36],
    1901          45 :                         is4[37], is4[38], is4[39], is4[40]) != 0) {
    1902           0 :             msg = errSprintf (nullptr);
    1903           0 :             meta->pds2.sect4.numInterval = (uChar) is4[41];
    1904           0 :             if (meta->pds2.sect4.numInterval != 1) {
    1905           0 :                errSprintf ("ERROR: in call to ParseTime from ParseSect4\n%s",
    1906             :                            msg);
    1907           0 :                errSprintf ("Most likely they didn't complete bytes 35-41 of "
    1908             :                            "Template 4.8\n");
    1909           0 :                free (msg);
    1910           0 :                meta->pds2.sect4.numInterval = 0;
    1911           0 :                return -1;
    1912             :             }
    1913           0 :             printf ("Warning: in call to ParseTime from ParseSect4\n%s", msg);
    1914           0 :             free (msg);
    1915           0 :             meta->pds2.sect4.validTime = (time_t) (meta->pds2.refTime +
    1916           0 :                                                    meta->pds2.sect4.foreSec);
    1917           0 :             printf ("Most likely they didn't complete bytes 35-41 of "
    1918             :                     "Template 4.8\n");
    1919             :          } else {
    1920          45 :             meta->pds2.sect4.numInterval = (uChar) is4[41];
    1921             :          }
    1922             : 
    1923             :          /* Added this check because some MOS grids didn't finish the
    1924             :           * template. */
    1925          45 :          if (meta->pds2.sect4.numInterval != 0) {
    1926          45 :             temp_ptr = realloc ((void *) meta->pds2.sect4.Interval,
    1927          45 :                                 meta->pds2.sect4.numInterval *
    1928             :                                 sizeof (sect4_IntervalType));
    1929          45 :             if (temp_ptr == nullptr) {
    1930           0 :                printf ("Ran out of memory.\n");
    1931           0 :                return -6;
    1932             :             }
    1933          45 :             meta->pds2.sect4.Interval = (sect4_IntervalType *) temp_ptr;
    1934          45 :             meta->pds2.sect4.numMissing = is4[42];
    1935          45 :             if (ns4 < 54 + (meta->pds2.sect4.numInterval-1)*12+1) {
    1936           0 :                 return -1;
    1937             :             }
    1938          90 :             for (i = 0; i < meta->pds2.sect4.numInterval; i++) {
    1939          45 :                meta->pds2.sect4.Interval[i].processID =
    1940          45 :                      (uChar) is4[46 + i * 12];
    1941          45 :                meta->pds2.sect4.Interval[i].incrType =
    1942          45 :                      (uChar) is4[47 + i * 12];
    1943          45 :                meta->pds2.sect4.Interval[i].timeRangeUnit =
    1944          45 :                      (uChar) is4[48 + i * 12];
    1945          45 :                meta->pds2.sect4.Interval[i].lenTime = is4[49 + i * 12];
    1946          45 :                meta->pds2.sect4.Interval[i].incrUnit =
    1947          45 :                      (uChar) is4[53 + i * 12];
    1948          45 :                meta->pds2.sect4.Interval[i].timeIncr =
    1949          45 :                      (uChar) is4[54 + i * 12];
    1950             :             }
    1951             :          } else {
    1952             : #ifdef DEBUG
    1953           0 :             printf ("Caution: Template 4.8 had no Intervals.\n");
    1954             : #endif
    1955           0 :             meta->pds2.sect4.numMissing = is4[42];
    1956             :          }
    1957          45 :          break;
    1958           0 :       case GS4_PERCENT_PNT: /* 4.6 */
    1959           0 :          if( ns4 < 35) {
    1960           0 :             return -1;
    1961             :          }
    1962           0 :          meta->pds2.sect4.percentile = is4[34];
    1963           0 :          break;
    1964           0 :       case GS4_PERCENT_TIME: /* 4.10 */
    1965           0 :          if (ns4 < 44) {
    1966           0 :             return -1;
    1967             :          }
    1968           0 :          meta->pds2.sect4.percentile = is4[34];
    1969           0 :          if (ParseTime (&(meta->pds2.sect4.validTime), is4[35], is4[37],
    1970           0 :                         is4[38], is4[39], is4[40], is4[41]) != 0) {
    1971           0 :             msg = errSprintf (nullptr);
    1972           0 :             meta->pds2.sect4.numInterval = (uChar) is4[42];
    1973           0 :             if (meta->pds2.sect4.numInterval != 1) {
    1974           0 :                errSprintf ("ERROR: in call to ParseTime from ParseSect4\n%s",
    1975             :                            msg);
    1976           0 :                errSprintf ("Most likely they didn't complete bytes 35-41 of "
    1977             :                            "Template 4.10\n");
    1978           0 :                free (msg);
    1979           0 :                meta->pds2.sect4.numInterval = 0;
    1980           0 :                return -1;
    1981             :             }
    1982           0 :             printf ("Warning: in call to ParseTime from ParseSect4\n%s", msg);
    1983           0 :             free (msg);
    1984           0 :             meta->pds2.sect4.validTime = (time_t) (meta->pds2.refTime +
    1985           0 :                                                    meta->pds2.sect4.foreSec);
    1986           0 :             printf ("Most likely they didn't complete bytes 35-41 of "
    1987             :                     "Template 4.10\n");
    1988             :          } else {
    1989           0 :             meta->pds2.sect4.numInterval = (uChar) is4[42];
    1990             :          }
    1991             : 
    1992             :          /* Added this check because some MOS grids didn't finish the
    1993             :           * template. */
    1994           0 :          if (meta->pds2.sect4.numInterval != 0) {
    1995           0 :             temp_ptr = realloc ((void *) meta->pds2.sect4.Interval,
    1996           0 :                                 meta->pds2.sect4.numInterval *
    1997             :                                 sizeof (sect4_IntervalType));
    1998           0 :             if (temp_ptr == nullptr) {
    1999           0 :                printf ("Ran out of memory.\n");
    2000           0 :                return -6;
    2001             :             }
    2002           0 :             meta->pds2.sect4.Interval = (sect4_IntervalType *) temp_ptr;
    2003           0 :             meta->pds2.sect4.numMissing = is4[43];
    2004           0 :             if (ns4 < 55 + (meta->pds2.sect4.numInterval-1)*12+1) {
    2005           0 :                 return -1;
    2006             :             }
    2007           0 :             for (i = 0; i < meta->pds2.sect4.numInterval; i++) {
    2008           0 :                meta->pds2.sect4.Interval[i].processID =
    2009           0 :                      (uChar) is4[47 + i * 12];
    2010           0 :                meta->pds2.sect4.Interval[i].incrType =
    2011           0 :                      (uChar) is4[48 + i * 12];
    2012           0 :                meta->pds2.sect4.Interval[i].timeRangeUnit =
    2013           0 :                      (uChar) is4[49 + i * 12];
    2014           0 :                meta->pds2.sect4.Interval[i].lenTime = is4[50 + i * 12];
    2015           0 :                meta->pds2.sect4.Interval[i].incrUnit =
    2016           0 :                      (uChar) is4[54 + i * 12];
    2017           0 :                meta->pds2.sect4.Interval[i].timeIncr =
    2018           0 :                      (uChar) is4[55 + i * 12];
    2019             :             }
    2020             :          } else {
    2021             : #ifdef DEBUG
    2022           0 :             printf ("Caution: Template 4.10 had no Intervals.\n");
    2023             : #endif
    2024           0 :             meta->pds2.sect4.numMissing = is4[43];
    2025             :          }
    2026           0 :          break;
    2027           0 :       case GS4_PROBABIL_PNT: /* 4.5 */
    2028           0 :          if (ns4 < 44) {
    2029           0 :             return -1;
    2030             :          }
    2031           0 :          meta->pds2.sect4.foreProbNum = (uChar) is4[34];
    2032           0 :          meta->pds2.sect4.numForeProbs = (uChar) is4[35];
    2033           0 :          meta->pds2.sect4.probType = (uChar) is4[36];
    2034           0 :          meta->pds2.sect4.lowerLimit.factor =
    2035           0 :                sbit_2Comp_oneByte((sChar) is4[37]);
    2036           0 :          meta->pds2.sect4.lowerLimit.value = sbit_2Comp_fourByte(is4[38]);
    2037           0 :          meta->pds2.sect4.upperLimit.factor =
    2038           0 :                sbit_2Comp_oneByte((sChar) is4[42]);
    2039           0 :          meta->pds2.sect4.upperLimit.value = sbit_2Comp_fourByte(is4[43]);
    2040           0 :          break;
    2041           0 :       case GS4_PROBABIL_TIME: /* 4.9 */
    2042           0 :          if (ns4 < 56) {
    2043           0 :             return -1;
    2044             :          }
    2045           0 :          meta->pds2.sect4.foreProbNum = (uChar) is4[34];
    2046           0 :          meta->pds2.sect4.numForeProbs = (uChar) is4[35];
    2047           0 :          meta->pds2.sect4.probType = (uChar) is4[36];
    2048           0 :          meta->pds2.sect4.lowerLimit.factor =
    2049           0 :                sbit_2Comp_oneByte((sChar) is4[37]);
    2050           0 :          meta->pds2.sect4.lowerLimit.value = sbit_2Comp_fourByte(is4[38]);
    2051           0 :          meta->pds2.sect4.upperLimit.factor =
    2052           0 :                sbit_2Comp_oneByte((sChar) is4[42]);
    2053           0 :          meta->pds2.sect4.upperLimit.value = sbit_2Comp_fourByte(is4[43]);
    2054           0 :          if (ParseTime (&(meta->pds2.sect4.validTime), is4[47], is4[49],
    2055           0 :                         is4[50], is4[51], is4[52], is4[53]) != 0) {
    2056           0 :             msg = errSprintf (nullptr);
    2057           0 :             meta->pds2.sect4.numInterval = (uChar) is4[54];
    2058           0 :             if (meta->pds2.sect4.numInterval != 1) {
    2059           0 :                errSprintf ("ERROR: in call to ParseTime from ParseSect4\n%s",
    2060             :                            msg);
    2061           0 :                errSprintf ("Most likely they didn't complete bytes 48-54 of "
    2062             :                            "Template 4.9\n");
    2063           0 :                free (msg);
    2064           0 :                meta->pds2.sect4.numInterval = 0;
    2065           0 :                return -1;
    2066             :             }
    2067           0 :             printf ("Warning: in call to ParseTime from ParseSect4\n%s", msg);
    2068           0 :             free (msg);
    2069           0 :             meta->pds2.sect4.validTime = (time_t) (meta->pds2.refTime +
    2070           0 :                                                    meta->pds2.sect4.foreSec);
    2071           0 :             printf ("Most likely they didn't complete bytes 48-54 of "
    2072             :                     "Template 4.9\n");
    2073             :          } else {
    2074           0 :             meta->pds2.sect4.numInterval = (uChar) is4[54];
    2075             :          }
    2076           0 :          temp_ptr = realloc ((void *) meta->pds2.sect4.Interval,
    2077           0 :                              meta->pds2.sect4.numInterval *
    2078             :                              sizeof (sect4_IntervalType));
    2079           0 :          if (temp_ptr == nullptr) {
    2080           0 :             printf ("Ran out of memory.\n");
    2081           0 :             return -6;
    2082             :          }
    2083           0 :          meta->pds2.sect4.Interval = (sect4_IntervalType *) temp_ptr;
    2084           0 :          meta->pds2.sect4.numMissing = is4[55];
    2085           0 :          if (ns4 < 67 + (meta->pds2.sect4.numInterval-1)*12+1) {
    2086           0 :             return -1;
    2087             :          }
    2088           0 :          for (i = 0; i < meta->pds2.sect4.numInterval; i++) {
    2089           0 :             meta->pds2.sect4.Interval[i].processID = (uChar) is4[59 + i * 12];
    2090           0 :             meta->pds2.sect4.Interval[i].incrType = (uChar) is4[60 + i * 12];
    2091           0 :             meta->pds2.sect4.Interval[i].timeRangeUnit =
    2092           0 :                   (uChar) is4[61 + i * 12];
    2093           0 :             meta->pds2.sect4.Interval[i].lenTime = is4[62 + i * 12];
    2094           0 :             meta->pds2.sect4.Interval[i].incrUnit = (uChar) is4[66 + i * 12];
    2095           0 :             meta->pds2.sect4.Interval[i].timeIncr = (uChar) is4[67 + i * 12];
    2096             :          }
    2097           0 :          break;
    2098           2 :       case GS4_STATISTIC_SPATIAL_AREA: /* 4.15 */
    2099             :             // TODO. Need to fetch
    2100             :             // 35 Statistical process used within the spatial area defined by octet 36 (see Code Table 4.10)
    2101             :             // 36 Type of spatial processing used to arrive at given data value from source data (see Code Table 4.15)
    2102             :             // 37 Number of data points used in spatial processing defined in octet 36
    2103           2 :             break;
    2104           9 :       case GS4_ANALYSIS_CHEMICAL: /* 4.40 */
    2105             :             // TODO
    2106           9 :             break;
    2107           1 :       case GS4_OPTICAL_PROPERTIES_AEROSOL: /* 4.48 */
    2108             :             // TODO
    2109           1 :             break;
    2110           0 :       default:
    2111           0 :          errSprintf ("Un-supported Template. %ld\n", is4[7]);
    2112           0 :          return -4;
    2113             :    }
    2114             : 
    2115             :    /* Do only that check at the end so that other meta fields are properly set */
    2116             :    /* otherwise we might do erroneous unit conversion as in */
    2117             :    /* https://github.com/OSGeo/gdal/issues/3158 */
    2118         444 :    if (is4[5] != 0) {
    2119             : #ifdef DEBUG
    2120           0 :       printf ("Un-supported template.\n  All Supported template "
    2121             :               "have 0 coordinate vertical values after template.");
    2122             : #endif
    2123           0 :       errSprintf ("Un-supported template.\n  All Supported template "
    2124             :                   "have 0 coordinate vertical values after template.");
    2125           0 :       return -4;
    2126             :    }
    2127             : 
    2128         444 :    return 0;
    2129             : }
    2130             : 
    2131             : /*****************************************************************************
    2132             :  * ParseSect5() --
    2133             :  *
    2134             :  * Arthur Taylor / MDL
    2135             :  *
    2136             :  * PURPOSE
    2137             :  *   To verify and parse section 5 data.
    2138             :  *
    2139             :  * ARGUMENTS
    2140             :  *    is5 = The unpacked section 5 array. (Input)
    2141             :  *    ns5 = The size of section 5. (Input)
    2142             :  *   meta = The structure to fill. (Output)
    2143             :  * xmissp = The primary missing value. (Input)
    2144             :  * xmisss = The secondary missing value. (Input)
    2145             :  *
    2146             :  * FILES/DATABASES: None
    2147             :  *
    2148             :  * RETURNS: int (could use errSprintf())
    2149             :  *  0 = OK
    2150             :  * -1 = ns5 is too small.
    2151             :  * -2 = unexpected values in is5.
    2152             :  * -6 = unsupported packing.
    2153             :  *
    2154             :  * HISTORY
    2155             :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
    2156             :  *
    2157             :  * NOTES
    2158             :  *****************************************************************************
    2159             :  */
    2160         457 : static int ParseSect5 (sInt4 *is5, sInt4 ns5, grib_MetaData *meta,
    2161             :                        float xmissp, float xmisss)
    2162             : {
    2163         457 :    if (ns5 < 22) {
    2164           0 :       return -1;
    2165             :    }
    2166         457 :    if (is5[4] != 5) {
    2167           0 :       errSprintf ("ERROR IS5 not labeled correctly. %ld\n", is5[5]);
    2168           0 :       return -2;
    2169             :    }
    2170         457 :    if ((is5[9] != GS5_SIMPLE) && (is5[9] != GS5_CMPLX) &&
    2171         263 :        (is5[9] != GS5_CMPLXSEC) && (is5[9] != GS5_IEEE) &&
    2172         101 :        (is5[9] != GS5_SPECTRAL) &&
    2173         101 :        (is5[9] != GS5_HARMONIC) && (is5[9] != GS5_JPEG2000) &&
    2174          48 :        (is5[9] != GS5_PNG) && (is5[9] != GS5_JPEG2000_ORG) &&
    2175           2 :        (is5[9] != GS5_PNG_ORG)) {
    2176           2 :       errSprintf ("Un-supported Packing? %ld\n", is5[9]);
    2177           2 :       return -6;
    2178             :    }
    2179         455 :    meta->gridAttrib.packType = (sInt4) is5[9];
    2180         455 :    meta->gridAttrib.f_maxmin = 0;
    2181         455 :    meta->gridAttrib.missPri = xmissp;
    2182         455 :    meta->gridAttrib.missSec = xmisss;
    2183         455 :    if ( (is5[9] == GS5_IEEE) || (is5[9] == GS5_SPECTRAL) || (is5[9] == GS5_HARMONIC)) {
    2184         126 :       meta->gridAttrib.fieldType = 0;
    2185         126 :       meta->gridAttrib.f_miss = 0;
    2186         126 :       return 0;
    2187             :    }
    2188         329 :    if (is5[20] > 1) {
    2189           0 :       errSprintf ("Invalid field type. %ld\n", is5[20]);
    2190           0 :       return -2;
    2191             :    }
    2192         329 :    MEMCPY_BIG (&meta->gridAttrib.refVal, &(is5[11]), 4);
    2193         329 :    meta->gridAttrib.ESF = is5[15];
    2194         329 :    meta->gridAttrib.DSF = is5[17];
    2195         329 :    meta->gridAttrib.fieldType = (uChar) is5[20];
    2196         329 :    if ((is5[9] == GS5_SIMPLE) ||
    2197         186 :        (is5[9] == GS5_JPEG2000) || (is5[9] == GS5_JPEG2000_ORG) ||
    2198         133 :        (is5[9] == GS5_PNG) || (is5[9] == GS5_PNG_ORG)) {
    2199         242 :       meta->gridAttrib.f_miss = 0;
    2200         242 :       return 0;
    2201             :    }
    2202             : 
    2203          87 :    myAssert( (is5[9] == GS5_CMPLX) || (is5[9] == GS5_CMPLXSEC) );
    2204             : 
    2205          87 :    if (ns5 < 23) {
    2206           0 :        return -1;
    2207             :    }
    2208          87 :    if (is5[22] > 2) {
    2209           0 :        errSprintf ("Invalid missing management type, f_miss = %ld\n",
    2210           0 :                    is5[22]);
    2211           0 :        return -2;
    2212             :    }
    2213          87 :    meta->gridAttrib.f_miss = (uChar) is5[22];
    2214             : 
    2215          87 :    return 0;
    2216             : }
    2217             : 
    2218             : /*****************************************************************************
    2219             :  * MetaParse() --
    2220             :  *
    2221             :  * Arthur Taylor / MDL
    2222             :  *
    2223             :  * PURPOSE
    2224             :  *   To parse all the meta data from a grib2 message.
    2225             :  *
    2226             :  * ARGUMENTS
    2227             :  *   meta = The structure to fill. (Output)
    2228             :  *    is0 = The unpacked section 0 array. (Input)
    2229             :  *    ns0 = The size of section 0. (Input)
    2230             :  *    is1 = The unpacked section 1 array. (Input)
    2231             :  *    ns1 = The size of section 1. (Input)
    2232             :  *    is2 = The unpacked section 2 array. (Input)
    2233             :  *    ns2 = The size of section 2. (Input)
    2234             :  *   rdat = The float data in section 2. (Input)
    2235             :  *  nrdat = Length of rdat. (Input)
    2236             :  *   idat = The integer data in section 2. (Input)
    2237             :  *  nidat = Length of idat. (Input)
    2238             :  *    is3 = The unpacked section 3 array. (Input)
    2239             :  *    ns3 = The size of section 3. (Input)
    2240             :  *    is4 = The unpacked section 4 array. (Input)
    2241             :  *    ns4 = The size of section 4. (Input)
    2242             :  *    is5 = The unpacked section 5 array. (Input)
    2243             :  *    ns5 = The size of section 5. (Input)
    2244             :  * grib_len = The length of the entire grib message. (Input)
    2245             :  * xmissp = The primary missing value. (Input)
    2246             :  * xmisss = The secondary missing value. (Input)
    2247             :  * simpVer = The version of the simple weather code to use when parsing the
    2248             :  *           WxString (if applicable). (Input)
    2249             :  *
    2250             :  * FILES/DATABASES: None
    2251             :  *
    2252             :  * RETURNS: int (could use errSprintf())
    2253             :  *   0 = OK
    2254             :  *  -1 = A dimension is too small.
    2255             :  *  -2 = unexpected values in a grib section.
    2256             :  *  -3 = un-supported map Projection.
    2257             :  *  -4 = un-supported Sect 4 template.
    2258             :  *  -5 = unsupported forecast time unit.
    2259             :  *  -6 = unsupported sect 5 packing.
    2260             :  * -10 = Something the driver can't handle yet.
    2261             :  *       (prodType != 0, f_sphere != 1, etc)
    2262             :  * -11 = Weather grid without a lookup table.
    2263             :  *
    2264             :  * HISTORY
    2265             :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
    2266             :  *
    2267             :  * NOTES
    2268             :  *****************************************************************************
    2269             :  */
    2270         457 : int MetaParse (grib_MetaData *meta, sInt4 *is0, sInt4 ns0,
    2271             :                sInt4 *is1, sInt4 ns1, sInt4 *is2, sInt4 ns2,
    2272             :                float *rdat, sInt4 nrdat, sInt4 *idat, sInt4 nidat,
    2273             :                sInt4 *is3, sInt4 ns3, sInt4 *is4, sInt4 ns4,
    2274             :                sInt4 *is5, sInt4 ns5, sInt4 grib_len,
    2275             :                float xmissp, float xmisss, int simpVer, CPL_UNUSED int simpWWA)
    2276             : {
    2277             :    int ierr;            /* The error code of a called routine */
    2278             :    /* char *element; *//* Holds the name of the current variable. */
    2279             :    /* char *comment; *//* Holds more comments about current variable. */
    2280             :    /* char *unitName; *//* Holds the name of the unit [K] [%] .. etc */
    2281             :    uChar probType;      /* The probability type */
    2282             :    double lowerProb;    /* The lower limit on probability forecast if
    2283             :                          * template 4.5 or 4.9 */
    2284             :    double upperProb;    /* The upper limit on probability forecast if
    2285             :                          * template 4.5 or 4.9 */
    2286             :    sInt4 lenTime;       /* Length of time for element (see 4.8 and 4.9) */
    2287         457 :    uChar timeRangeUnit = 1;
    2288             :    uChar incrType;
    2289             :    uChar statProcessID; /* Statistical process id or 255 for missing */
    2290             :    uChar fstSurfType;   /* Type of the first fixed surface. */
    2291             :    sInt4 value;         /* The scaled value from GRIB2 file. */
    2292             :    sChar scale;         /* Surface scale as opposed to probility factor. */
    2293             :    double fstSurfValue; /* Value of first fixed surface. */
    2294             :    sChar f_fstValue;    /* flag if FstValue is valid. */
    2295             :    uChar sndSurfType;   /* Type of the second fixed surface. */
    2296             :    double sndSurfValue; /* Value of second fixed surface. */
    2297             :    sChar f_sndValue;    /* flag if SndValue is valid. */
    2298             : 
    2299         457 :    if ((ierr = ParseSect0 (is0, ns0, grib_len, meta)) != 0) {
    2300           0 :       preErrSprintf ("Parse error Section 0\n");
    2301             :       //return ierr;
    2302             :    }
    2303         457 :    if ((ierr = ParseSect1 (is1, ns1, meta)) != 0) {
    2304           0 :      preErrSprintf ("Parse error Section 1\n");
    2305             :       //return ierr;
    2306             :    }
    2307         457 :    if (ns2 < 7) {
    2308           0 :       errSprintf ("ns2 was too small in MetaParse\n");
    2309             :       //return -1;
    2310             :    }
    2311         457 :    meta->pds2.f_sect2 = (uChar) (is2[0] != 0);
    2312         457 :    if (meta->pds2.f_sect2) {
    2313           2 :       meta->pds2.sect2NumGroups = is2[7 - 1];
    2314             :    } else {
    2315         455 :       meta->pds2.sect2NumGroups = 0;
    2316             :    }
    2317         457 :    if ((ierr = ParseSect3 (is3, ns3, meta)) != 0) {
    2318           2 :       preErrSprintf ("Parse error Section 3\n");
    2319             :       //return ierr;
    2320             :    }
    2321         457 :    if (IsData_NDFD (meta->center, meta->subcenter)) {
    2322          27 :       meta->gds.hdatum = 1;
    2323             :    }
    2324         457 :    if (meta->gds.f_sphere != 1) {
    2325         334 :       errSprintf ("Driver Filter: Can only handle spheres.\n");
    2326             :       //return -10;
    2327             :    }
    2328         457 :    if ((ierr = ParseSect4 (is4, ns4, meta)) != 0) {
    2329           5 :       preErrSprintf ("Parse error Section 4\n");
    2330             :       //return ierr;
    2331             :    }
    2332         457 :    if ((ierr = ParseSect5 (is5, ns5, meta, xmissp, xmisss)) != 0) {
    2333           2 :       preErrSprintf ("Parse error Section 5\n");
    2334             :       //return ierr;
    2335             :    }
    2336             :    /* Compute ElementName. */
    2337         457 :    if (meta->element) {
    2338           0 :       free (meta->element);
    2339           0 :       meta->element = nullptr;
    2340             :    }
    2341         457 :    if (meta->unitName) {
    2342           0 :       free (meta->unitName);
    2343           0 :       meta->unitName = nullptr;
    2344             :    }
    2345         457 :    if (meta->comment) {
    2346           0 :       free (meta->comment);
    2347           0 :       meta->comment = nullptr;
    2348             :    }
    2349             : 
    2350         457 :    if ((meta->pds2.sect4.templat == GS4_PROBABIL_TIME) ||
    2351         457 :        (meta->pds2.sect4.templat == GS4_PROBABIL_PNT)) {
    2352           0 :       probType = meta->pds2.sect4.probType;
    2353           0 :       lowerProb = meta->pds2.sect4.lowerLimit.value *
    2354           0 :             pow (10.0, -1 * meta->pds2.sect4.lowerLimit.factor);
    2355           0 :       upperProb = meta->pds2.sect4.upperLimit.value *
    2356           0 :             pow (10.0, -1 * meta->pds2.sect4.upperLimit.factor);
    2357             :    } else {
    2358         457 :       probType = 0;
    2359         457 :       lowerProb = 0;
    2360         457 :       upperProb = 0;
    2361             :    }
    2362         457 :    if (meta->pds2.sect4.numInterval > 0) {
    2363             :       /* Try to convert lenTime to hourly. */
    2364          49 :       timeRangeUnit = meta->pds2.sect4.Interval[0].timeRangeUnit;
    2365          49 :       if (meta->pds2.sect4.Interval[0].timeRangeUnit == 255) {
    2366           0 :          lenTime = (sInt4) ((meta->pds2.sect4.validTime -
    2367           0 :                              meta->pds2.sect4.foreSec -
    2368           0 :                              meta->pds2.refTime) / 3600);
    2369          49 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 0) {
    2370           0 :          lenTime = (sInt4) (meta->pds2.sect4.Interval[0].lenTime / 60.);
    2371           0 :          timeRangeUnit = 1;
    2372          49 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 1) {
    2373          49 :          lenTime = meta->pds2.sect4.Interval[0].lenTime;
    2374          49 :          timeRangeUnit = 1;
    2375           0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 2) {
    2376           0 :          lenTime = meta->pds2.sect4.Interval[0].lenTime * 24;
    2377           0 :          timeRangeUnit = 1;
    2378           0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 10) {
    2379           0 :          lenTime = meta->pds2.sect4.Interval[0].lenTime * 3;
    2380           0 :          timeRangeUnit = 1;
    2381           0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 11) {
    2382           0 :          lenTime = meta->pds2.sect4.Interval[0].lenTime * 6;
    2383           0 :          timeRangeUnit = 1;
    2384           0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 12) {
    2385           0 :          lenTime = meta->pds2.sect4.Interval[0].lenTime * 12;
    2386           0 :          timeRangeUnit = 1;
    2387           0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 13) {
    2388           0 :          lenTime = (sInt4) (meta->pds2.sect4.Interval[0].lenTime / 3600.);
    2389           0 :          timeRangeUnit = 1;
    2390           0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 3) {  /* month */
    2391           0 :          lenTime = meta->pds2.sect4.Interval[0].lenTime;
    2392           0 :          timeRangeUnit = 3;
    2393           0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 4) {  /* year */
    2394           0 :          lenTime = meta->pds2.sect4.Interval[0].lenTime;
    2395           0 :          timeRangeUnit = 4;
    2396           0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 5) {  /* decade */
    2397           0 :          lenTime = meta->pds2.sect4.Interval[0].lenTime * 10;
    2398           0 :          timeRangeUnit = 4;
    2399           0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 6) {  /* normal */
    2400           0 :          lenTime = meta->pds2.sect4.Interval[0].lenTime * 30;
    2401           0 :          timeRangeUnit = 4;
    2402           0 :       } else if (meta->pds2.sect4.Interval[0].timeRangeUnit == 7) {  /* century */
    2403           0 :          lenTime = meta->pds2.sect4.Interval[0].lenTime * 100;
    2404           0 :          timeRangeUnit = 4;
    2405             :       } else {
    2406           0 :          lenTime = 0;
    2407           0 :          printf ("Can't handle this timeRangeUnit\n");
    2408           0 :          myAssert (meta->pds2.sect4.Interval[0].timeRangeUnit == 1);
    2409             :       }
    2410             : /*
    2411             :       } else {
    2412             :          lenTime = 255;
    2413             :       }
    2414             :       if (lenTime == 255) {
    2415             :          lenTime = (meta->pds2.sect4.validTime - meta->pds2.sect4.foreSec -
    2416             :                     meta->pds2.refTime) / 3600;
    2417             :       }
    2418             : */
    2419          49 :       if (lenTime == GRIB2MISSING_s4) {
    2420           0 :          lenTime = 0;
    2421             :       }
    2422          49 :       incrType = meta->pds2.sect4.Interval[0].incrType;
    2423          49 :       statProcessID = meta->pds2.sect4.Interval[0].processID;
    2424             :    } else {
    2425         408 :       lenTime = 0;
    2426         408 :       timeRangeUnit = 1;
    2427         408 :       incrType = 255;
    2428         408 :       statProcessID = 255;
    2429             :    }
    2430             : 
    2431         457 :    if ((meta->pds2.sect4.templat == GS4_RADAR) || (meta->pds2.sect4.templat == GS4_SATELLITE)
    2432         457 :        || (meta->pds2.sect4.templat == 254) || (meta->pds2.sect4.templat == 1000) || (meta->pds2.sect4.templat == 1001)
    2433         457 :        || (meta->pds2.sect4.templat == 1002)) {
    2434           0 :       fstSurfValue = 0;
    2435           0 :       f_fstValue = 0;
    2436           0 :       fstSurfType = 0;
    2437           0 :       sndSurfValue = 0;
    2438           0 :       f_sndValue = 0;
    2439             :    } else {
    2440         457 :       fstSurfType = meta->pds2.sect4.fstSurfType;
    2441         457 :       scale = meta->pds2.sect4.fstSurfScale;
    2442         914 :       if (meta->pds2.sect4.fstSurfValue >= std::numeric_limits<sInt4>::max() ||
    2443         457 :           meta->pds2.sect4.fstSurfValue <= std::numeric_limits<sInt4>::min()) {
    2444             :          // Out of range, so just call it missing.
    2445           0 :          preErrSprintf ("fstSurfValue out of range\n");
    2446           0 :          value = GRIB2MISSING_s4;
    2447             :       } else {
    2448         457 :         value = static_cast<sInt4>(meta->pds2.sect4.fstSurfValue);
    2449             :       }
    2450         457 :       if ((value == GRIB2MISSING_s4) || (scale == GRIB2MISSING_s1) ||
    2451             :           (fstSurfType == GRIB2MISSING_u1)) {
    2452          21 :          fstSurfValue = 0;
    2453          21 :          f_fstValue = 1;
    2454             :       } else {
    2455         436 :          fstSurfValue = value * pow (10.0, -1 * scale);
    2456         436 :          f_fstValue = 1;
    2457             :       }
    2458         457 :       sndSurfType = meta->pds2.sect4.sndSurfType;
    2459         457 :       scale = meta->pds2.sect4.sndSurfScale;
    2460         914 :       if (meta->pds2.sect4.sndSurfValue < std::numeric_limits<int>::max() &&
    2461         457 :           meta->pds2.sect4.sndSurfValue > std::numeric_limits<int>::min()) {
    2462         457 :          value = static_cast<int>(meta->pds2.sect4.sndSurfValue);
    2463             :       } else {
    2464             :          // sndSurfValue is out of range, so just call it missing.
    2465             :          // TODO(schwehr): Consider using a tmp double if the scale will
    2466             :          // make the resulting sndSurfValue be within range.
    2467           0 :          preErrSprintf ("sndSurfValue out of range\n");
    2468           0 :          value = GRIB2MISSING_s4;
    2469             :       }
    2470         457 :       if ((value == GRIB2MISSING_s4) || (scale == GRIB2MISSING_s1) ||
    2471             :           (sndSurfType == GRIB2MISSING_u1)) {
    2472         452 :          sndSurfValue = 0;
    2473         452 :          f_sndValue = 0;
    2474             :       } else {
    2475           5 :          sndSurfValue = value * pow (10.0, -1 * scale);
    2476           5 :          f_sndValue = 1;
    2477             :       }
    2478             :    }
    2479             : 
    2480         457 :    ParseElemName (meta->pds2.mstrVersion, meta->center, meta->subcenter, meta->pds2.prodType,
    2481         457 :                   meta->pds2.sect4.templat, meta->pds2.sect4.cat,
    2482         457 :                   meta->pds2.sect4.subcat, lenTime, timeRangeUnit, statProcessID,
    2483         457 :                   incrType, meta->pds2.sect4.genID, probType, lowerProb, upperProb,
    2484         457 :                   meta->pds2.sect4.derivedFcst,
    2485             :                   &(meta->element), &(meta->comment), &(meta->unitName),
    2486         457 :                   &(meta->convert), meta->pds2.sect4.percentile,
    2487         457 :                   meta->pds2.sect4.genProcess,
    2488             :                   f_fstValue, fstSurfValue, f_sndValue, sndSurfValue);
    2489             : #ifdef DEBUG
    2490             : /*
    2491             :    printf ("Element: %s\nunitName: %s\ncomment: %s\n", meta->element,
    2492             :            meta->comment, meta->unitName);
    2493             : */
    2494             : #endif
    2495             : 
    2496         457 :    if (! f_fstValue) {
    2497           0 :       reallocSprintf (&(meta->shortFstLevel), "0 undefined");
    2498           0 :       reallocSprintf (&(meta->longFstLevel), "0.000[-] undefined ()");
    2499             :    } else {
    2500         457 :       ParseLevelName (meta->center, meta->subcenter, fstSurfType,
    2501             :                       fstSurfValue, f_sndValue, sndSurfValue,
    2502             :                       &(meta->shortFstLevel), &(meta->longFstLevel));
    2503             :    }
    2504             : 
    2505             :    /* Continue parsing section 2 data. */
    2506         457 :    if (meta->pds2.f_sect2) {
    2507           2 :       MetaSect2Free (meta);
    2508           2 :       if (strcmp (meta->element, "Wx") == 0) {
    2509           0 :          meta->pds2.sect2.ptrType = GS2_WXTYPE;
    2510           0 :          if ((ierr = ParseSect2_Wx (rdat, nrdat, idat, nidat,
    2511           0 :                                     &(meta->pds2.sect2.wx), simpVer)) != 0) {
    2512           0 :             preErrSprintf ("Parse error Section 2 : Weather Data\n");
    2513           0 :             return ierr;
    2514             :          }
    2515           2 :       } else if (strcmp (meta->element, "WWA") == 0) {
    2516           0 :          meta->pds2.sect2.ptrType = GS2_HAZARD;
    2517           0 :          if ((ierr = ParseSect2_Hazard (rdat, nrdat, idat, nidat,
    2518           0 :                                     &(meta->pds2.sect2.hazard), simpWWA)) != 0) {
    2519           0 :             preErrSprintf ("Parse error Section 2 : Hazard Data\n");
    2520           0 :             return ierr;
    2521             :          }
    2522             :       } else {
    2523           2 :          meta->pds2.sect2.ptrType = GS2_UNKNOWN;
    2524           2 :          if ((ierr = ParseSect2_Unknown (rdat, nrdat, idat, nidat, meta))
    2525           2 :              != 0) {
    2526           0 :             preErrSprintf ("Parse error Section 2 : Unknown Data type\n");
    2527             :             //return ierr;
    2528             :          }
    2529             :       }
    2530             :    } else {
    2531         455 :       if (strcmp (meta->element, "Wx") == 0) {
    2532           0 :          errSprintf ("Weather grid does not have look up table?");
    2533             :          //return -11;
    2534             :       }
    2535         455 :       if (strcmp (meta->element, "WWA") == 0) {
    2536           0 :          errSprintf ("Hazard grid does not have look up table?");
    2537             :          //return -11;
    2538             :       }
    2539             :    }
    2540         457 :    return 0;
    2541             : }
    2542             : 
    2543             : /*****************************************************************************
    2544             :  * ParseGridNoMiss() --
    2545             :  *
    2546             :  * Arthur Taylor / MDL
    2547             :  *
    2548             :  * PURPOSE
    2549             :  *   A helper function for ParseGrid.  In this particular case it is dealing
    2550             :  * with a field that has NO missing value type.
    2551             :  *   Walks through either a float or an integer grid, computing the min/max
    2552             :  * values in the grid, and converts the units. It uses gridAttrib info for the
    2553             :  * missing values and it updates gridAttrib with the observed min/max values.
    2554             :  *
    2555             :  * ARGUMENTS
    2556             :  *    attrib = Grid Attribute structure already filled in (Input/Output)
    2557             :  * grib_Data = The place to store the grid data. (Output)
    2558             :  *    Nx, Ny = The dimensions of the grid (Input)
    2559             :  *      iain = Place to find data if it is an Integer (or float). (Input)
    2560             :  *     unitM = M in unit conversion equation y(new) = m x(orig) + b (Input)
    2561             :  *     unitB = B in unit conversion equation y(new) = m x(orig) + b (Input)
    2562             :  *    f_txtType = true if we have a valid wx/hazard type. (Input)
    2563             :  *  txt_dataLen = Length of text table
    2564             :  *  txt_f_valid = whether that entry is used/valid. (Input)
    2565             :  *    startX = The start of the X values. (Input)
    2566             :  *    startY = The start of the Y values. (Input)
    2567             :  *     subNx = The Nx dimension of the subgrid (Input)
    2568             :  *     subNy = The Ny dimension of the subgrid (Input)
    2569             :  *
    2570             :  * FILES/DATABASES: None
    2571             :  *
    2572             :  * RETURNS: void
    2573             :  *
    2574             :  * HISTORY
    2575             :  *  12/2002 Arthur Taylor (MDL/RSIS): Created to optimize part of ParseGrid.
    2576             :  *   5/2003 AAT: Added ability to see if wxType occurs.  If so sets table
    2577             :  *          valid to 2, otherwise leaves it at 1.  If table valid is 0 then
    2578             :  *          sets value to missing value (if applicable).
    2579             :  *   2/2004 AAT: Added the subgrid capability.
    2580             :  *
    2581             :  * NOTES
    2582             :  * 1) Don't have to check if value became missing value, because we can check
    2583             :  *    if missing falls in the range of the min/max converted units.  If
    2584             :  *    missing does fall in that range we need to move missing.
    2585             :  *    (See f_readjust in ParseGrid)
    2586             :  *****************************************************************************
    2587             :  */
    2588         133 : static void ParseGridNoMiss (gridAttribType *attrib, double *grib_Data,
    2589             :                              sInt4 Nx, sInt4 Ny, sInt4 *iain,
    2590             :                              double unitM, double unitB,
    2591             :                              uChar f_txtType, uInt4 txt_dataLen,
    2592             :                              uChar *txt_f_valid, int startX, int startY,
    2593             :                              int subNx, int subNy)
    2594             : {
    2595             :    sInt4 x, y;          /* Where we are in the grid. */
    2596             :    double value;        /* The data in the new units. */
    2597         133 :    uChar f_maxmin = 0;  /* Flag if max/min is valid yet. */
    2598             :    uInt4 index;         /* Current index into Wx table. */
    2599         133 :    sInt4 *itemp = nullptr;
    2600         133 :    float *ftemp = nullptr;
    2601             : 
    2602             :    /* Resolve possibility that the data is an integer or a float and find
    2603             :     * max/min values. (see note 1) */
    2604        5955 :    for (y = 0; y < subNy; y++) {
    2605        5822 :       if (((startY + y - 1) < 0) || ((startY + y - 1) >= Ny)) {
    2606           0 :          for (x = 0; x < subNx; x++) {
    2607           0 :             *grib_Data++ = 9999;
    2608             :          }
    2609             :       } else {
    2610        5822 :          if (attrib->fieldType) {
    2611        2111 :             itemp = iain + (startY + y - 1) * Nx + (startX - 1);
    2612             :          } else {
    2613        3711 :             ftemp = ((float *) iain) + (startY + y - 1) * Nx + (startX - 1);
    2614             :          }
    2615     5803070 :          for (x = 0; x < subNx; x++) {
    2616     5797250 :             if (((startX + x - 1) < 0) || ((startX + x - 1) >= Nx)) {
    2617           0 :                *grib_Data++ = 9999;
    2618             :             } else {
    2619             :                /* Convert the units. */
    2620     5797250 :                if (attrib->fieldType) {
    2621      546377 :                   if (unitM == -10) {
    2622           0 :                      value = pow (10.0, (*itemp++));
    2623             :                   } else {
    2624      546377 :                      value = unitM * (*itemp++) + unitB;
    2625             :                   }
    2626             :                } else {
    2627     5250870 :                   if (unitM == -10) {
    2628           0 :                      value = pow (10.0, (double) (*ftemp++));
    2629             :                   } else {
    2630     5250870 :                      value = unitM * (*ftemp++) + unitB;
    2631             :                   }
    2632             :                }
    2633     5797250 :                if (f_txtType) {
    2634           0 :                   index = (uInt4) value;
    2635           0 :                   if (index < txt_dataLen) {
    2636           0 :                      if (txt_f_valid[index] == 1) {
    2637           0 :                         txt_f_valid[index] = 2;
    2638           0 :                      } else if (txt_f_valid[index] == 0) {
    2639             :                         /* Table is not valid here so set value to missing? */
    2640             :                         /* No missing value, so use index = WxType->dataLen? */
    2641             :                         /* No... set f_valid to 3 so we know we used this
    2642             :                          * invalid element, then handle it in degrib2.c ::
    2643             :                          * ReadGrib2Record() where we set it back to 0. */
    2644           0 :                         txt_f_valid[index] = 3;
    2645             :                      }
    2646             :                   }
    2647             :                }
    2648     5797250 :                if (f_maxmin) {
    2649     5797110 :                   if (value < attrib->min) {
    2650        1007 :                      attrib->min = value;
    2651     5796110 :                   } else if (value > attrib->max) {
    2652        1919 :                      attrib->max = value;
    2653             :                   }
    2654             :                } else {
    2655         133 :                   attrib->min = attrib->max = value;
    2656         133 :                   f_maxmin = 1;
    2657             :                }
    2658     5797250 :                *grib_Data++ = value;
    2659             :             }
    2660             :          }
    2661             :       }
    2662             :    }
    2663         133 :    attrib->f_maxmin = f_maxmin;
    2664         133 : }
    2665             : 
    2666             : /*****************************************************************************
    2667             :  * ParseGridPrimMiss() --
    2668             :  *
    2669             :  * Arthur Taylor / MDL
    2670             :  *
    2671             :  * PURPOSE
    2672             :  *   A helper function for ParseGrid.  In this particular case it is dealing
    2673             :  * with a field that has primary missing value type.
    2674             :  *   Walks through either a float or an integer grid, computing the min/max
    2675             :  * values in the grid, and converts the units. It uses gridAttrib info for the
    2676             :  * missing values and it updates gridAttrib with the observed min/max values.
    2677             :  *
    2678             :  * ARGUMENTS
    2679             :  *    attrib = sect 5 structure already filled in by ParseSect5 (In/Output)
    2680             :  * grib_Data = The place to store the grid data. (Output)
    2681             :  *    Nx, Ny = The dimensions of the grid (Input)
    2682             :  *      iain = Place to find data if it is an Integer (or float). (Input)
    2683             :  *     unitM = M in unit conversion equation y(new) = m x(orig) + b (Input)
    2684             :  *     unitB = B in unit conversion equation y(new) = m x(orig) + b (Input)
    2685             :  *    f_txtType = true if we have a valid wx/hazard type. (Input)
    2686             :  *  txt_dataLen = Length of text table
    2687             :  *  txt_f_valid = whether that entry is used/valid. (Input)
    2688             :  *    startX = The start of the X values. (Input)
    2689             :  *    startY = The start of the Y values. (Input)
    2690             :  *     subNx = The Nx dimension of the subgrid (Input)
    2691             :  *     subNy = The Ny dimension of the subgrid (Input)
    2692             :  *
    2693             :  * FILES/DATABASES: None
    2694             :  *
    2695             :  * RETURNS: void
    2696             :  *
    2697             :  * HISTORY
    2698             :  *  12/2002 Arthur Taylor (MDL/RSIS): Created to optimize part of ParseGrid.
    2699             :  *   5/2003 AAT: Added ability to see if wxType occurs.  If so sets table
    2700             :  *          valid to 2, otherwise leaves it at 1.  If table valid is 0 then
    2701             :  *          sets value to missing value (if applicable).
    2702             :  *   2/2004 AAT: Added the subgrid capability.
    2703             :  *
    2704             :  * NOTES
    2705             :  * 1) Don't have to check if value became missing value, because we can check
    2706             :  *    if missing falls in the range of the min/max converted units.  If
    2707             :  *    missing does fall in that range we need to move missing.
    2708             :  *    (See f_readjust in ParseGrid)
    2709             :  *****************************************************************************
    2710             :  */
    2711          24 : static void ParseGridPrimMiss (gridAttribType *attrib, double *grib_Data,
    2712             :                                sInt4 Nx, sInt4 Ny, sInt4 *iain,
    2713             :                                double unitM, double unitB, sInt4 *missCnt,
    2714             :                                uChar f_txtType, uInt4 txt_dataLen,
    2715             :                                uChar *txt_f_valid,
    2716             :                                int startX, int startY, int subNx, int subNy)
    2717             : {
    2718             :    sInt4 x, y;          /* Where we are in the grid. */
    2719             :    double value;        /* The data in the new units. */
    2720          24 :    uChar f_maxmin = 0;  /* Flag if max/min is valid yet. */
    2721             :    uInt4 index;         /* Current index into Wx table. */
    2722          24 :    sInt4 *itemp = nullptr;
    2723          24 :    float *ftemp = nullptr;
    2724             : /*   float *ain = (float *) iain;*/
    2725             : 
    2726             :    /* Resolve possibility that the data is an integer or a float and find
    2727             :     * max/min values. (see note 1) */
    2728        3196 :    for (y = 0; y < subNy; y++) {
    2729        3172 :       if (((startY + y - 1) < 0) || ((startY + y - 1) >= Ny)) {
    2730           0 :          for (x = 0; x < subNx; x++) {
    2731           0 :             *grib_Data++ = attrib->missPri;
    2732           0 :             (*missCnt)++;
    2733             :          }
    2734             :       } else {
    2735        3172 :          if (attrib->fieldType) {
    2736           7 :             itemp = iain + (startY + y - 1) * Nx + (startX - 1);
    2737             :          } else {
    2738        3165 :             ftemp = ((float *) iain) + (startY + y - 1) * Nx + (startX - 1);
    2739             :          }
    2740     2377310 :          for (x = 0; x < subNx; x++) {
    2741     2374130 :             if (((startX + x - 1) < 0) || ((startX + x - 1) >= Nx)) {
    2742           0 :                *grib_Data++ = attrib->missPri;
    2743           0 :                (*missCnt)++;
    2744             :             } else {
    2745     2374130 :                if (attrib->fieldType) {
    2746          13 :                   value = (*itemp++);
    2747             :                } else {
    2748     2374120 :                   value = (*ftemp++);
    2749             :                }
    2750             : 
    2751             :                /* Make sure value is not a missing value when converting
    2752             :                 * units, and while computing max/min. */
    2753     2374130 :                if (value == attrib->missPri) {
    2754     1378840 :                   (*missCnt)++;
    2755             :                } else {
    2756             :                   /* Convert the units. */
    2757      995295 :                   if (unitM == -10) {
    2758           0 :                      value = pow (10.0, value);
    2759             :                   } else {
    2760      995295 :                      value = unitM * value + unitB;
    2761             :                   }
    2762      995295 :                   if (f_txtType) {
    2763           0 :                      index = (uInt4) value;
    2764           0 :                      if (index < txt_dataLen) {
    2765           0 :                         if (txt_f_valid[index]) {
    2766           0 :                            txt_f_valid[index] = 2;
    2767             :                         } else {
    2768             :                            /* Table is not valid here so set value to missPri
    2769             :                             */
    2770           0 :                            value = attrib->missPri;
    2771           0 :                            (*missCnt)++;
    2772             :                         }
    2773             :                      }
    2774             :                   }
    2775      995295 :                   if ((!f_txtType) || (value != attrib->missPri)) {
    2776      995295 :                      if (f_maxmin) {
    2777      995274 :                         if (value < attrib->min) {
    2778         199 :                            attrib->min = value;
    2779      995075 :                         } else if (value > attrib->max) {
    2780          94 :                            attrib->max = value;
    2781             :                         }
    2782             :                      } else {
    2783          21 :                         attrib->min = attrib->max = value;
    2784          21 :                         f_maxmin = 1;
    2785             :                      }
    2786             :                   }
    2787             :                }
    2788     2374130 :                *grib_Data++ = value;
    2789             :             }
    2790             :          }
    2791             :       }
    2792             :    }
    2793          24 :    attrib->f_maxmin = f_maxmin;
    2794          24 : }
    2795             : 
    2796             : /*****************************************************************************
    2797             :  * ParseGridSecMiss() --
    2798             :  *
    2799             :  * Arthur Taylor / MDL
    2800             :  *
    2801             :  * PURPOSE
    2802             :  *   A helper function for ParseGrid.  In this particular case it is dealing
    2803             :  * with a field that has NO missing value type.
    2804             :  *   Walks through either a float or an integer grid, computing the min/max
    2805             :  * values in the grid, and converts the units. It uses gridAttrib info for the
    2806             :  * missing values and it updates gridAttrib with the observed min/max values.
    2807             :  *
    2808             :  * ARGUMENTS
    2809             :  *    attrib = sect 5 structure already filled in by ParseSect5 (In/Output)
    2810             :  * grib_Data = The place to store the grid data. (Output)
    2811             :  *    Nx, Ny = The dimensions of the grid (Input)
    2812             :  *      iain = Place to find data if it is an Integer (or float). (Input)
    2813             :  *     unitM = M in unit conversion equation y(new) = m x(orig) + b (Input)
    2814             :  *     unitB = B in unit conversion equation y(new) = m x(orig) + b (Input)
    2815             :  *    f_txtType = true if we have a valid wx/hazard type. (Input)
    2816             :  *  txt_dataLen = Length of text table
    2817             :  *  txt_f_valid = whether that entry is used/valid. (Input)
    2818             :  *    startX = The start of the X values. (Input)
    2819             :  *    startY = The start of the Y values. (Input)
    2820             :  *     subNx = The Nx dimension of the subgrid (Input)
    2821             :  *     subNy = The Ny dimension of the subgrid (Input)
    2822             :  *
    2823             :  * FILES/DATABASES: None
    2824             :  *
    2825             :  * RETURNS: void
    2826             :  *
    2827             :  * HISTORY
    2828             :  *  12/2002 Arthur Taylor (MDL/RSIS): Created to optimize part of ParseGrid.
    2829             :  *   5/2003 AAT: Added ability to see if wxType occurs.  If so sets table
    2830             :  *          valid to 2, otherwise leaves it at 1.  If table valid is 0 then
    2831             :  *          sets value to missing value (if applicable).
    2832             :  *   2/2004 AAT: Added the subgrid capability.
    2833             :  *
    2834             :  * NOTES
    2835             :  * 1) Don't have to check if value became missing value, because we can check
    2836             :  *    if missing falls in the range of the min/max converted units.  If
    2837             :  *    missing does fall in that range we need to move missing.
    2838             :  *    (See f_readjust in ParseGrid)
    2839             :  *****************************************************************************
    2840             :  */
    2841           0 : static void ParseGridSecMiss (gridAttribType *attrib, double *grib_Data,
    2842             :                               sInt4 Nx, sInt4 Ny, sInt4 *iain,
    2843             :                               double unitM, double unitB, sInt4 *missCnt,
    2844             :                               uChar f_txtType, uInt4 txt_dataLen,
    2845             :                               uChar *txt_f_valid,
    2846             :                               int startX, int startY, int subNx, int subNy)
    2847             : {
    2848             :    sInt4 x, y;          /* Where we are in the grid. */
    2849             :    double value;        /* The data in the new units. */
    2850           0 :    uChar f_maxmin = 0;  /* Flag if max/min is valid yet. */
    2851             :    uInt4 index;         /* Current index into Wx table. */
    2852           0 :    sInt4 *itemp = nullptr;
    2853           0 :    float *ftemp = nullptr;
    2854             : /*   float *ain = (float *) iain;*/
    2855             : 
    2856             :    /* Resolve possibility that the data is an integer or a float and find
    2857             :     * max/min values. (see note 1) */
    2858           0 :    for (y = 0; y < subNy; y++) {
    2859           0 :       if (((startY + y - 1) < 0) || ((startY + y - 1) >= Ny)) {
    2860           0 :          for (x = 0; x < subNx; x++) {
    2861           0 :             *grib_Data++ = attrib->missPri;
    2862           0 :             (*missCnt)++;
    2863             :          }
    2864             :       } else {
    2865           0 :          if (attrib->fieldType) {
    2866           0 :             itemp = iain + (startY + y - 1) * Nx + (startX - 1);
    2867             :          } else {
    2868           0 :             ftemp = ((float *) iain) + (startY + y - 1) * Nx + (startX - 1);
    2869             :          }
    2870           0 :          for (x = 0; x < subNx; x++) {
    2871           0 :             if (((startX + x - 1) < 0) || ((startX + x - 1) >= Nx)) {
    2872           0 :                *grib_Data++ = attrib->missPri;
    2873           0 :                (*missCnt)++;
    2874             :             } else {
    2875           0 :                if (attrib->fieldType) {
    2876           0 :                   value = (*itemp++);
    2877             :                } else {
    2878           0 :                   value = (*ftemp++);
    2879             :                }
    2880             : 
    2881             :                /* Make sure value is not a missing value when converting
    2882             :                 * units, and while computing max/min. */
    2883           0 :                if ((value == attrib->missPri) || (value == attrib->missSec)) {
    2884           0 :                   (*missCnt)++;
    2885             :                } else {
    2886             :                   /* Convert the units. */
    2887           0 :                   if (unitM == -10) {
    2888           0 :                      value = pow (10.0, value);
    2889             :                   } else {
    2890           0 :                      value = unitM * value + unitB;
    2891             :                   }
    2892           0 :                   if (f_txtType) {
    2893           0 :                      index = (uInt4) value;
    2894           0 :                      if (index < txt_dataLen) {
    2895           0 :                         if (txt_f_valid[index]) {
    2896           0 :                            txt_f_valid[index] = 2;
    2897             :                         } else {
    2898             :                            /* Table is not valid here so set value to missPri
    2899             :                             */
    2900           0 :                            value = attrib->missPri;
    2901           0 :                            (*missCnt)++;
    2902             :                         }
    2903             :                      }
    2904             :                   }
    2905           0 :                   if ((!f_txtType) || (value != attrib->missPri)) {
    2906           0 :                      if (f_maxmin) {
    2907           0 :                         if (value < attrib->min) {
    2908           0 :                            attrib->min = value;
    2909           0 :                         } else if (value > attrib->max) {
    2910           0 :                            attrib->max = value;
    2911             :                         }
    2912             :                      } else {
    2913           0 :                         attrib->min = attrib->max = value;
    2914           0 :                         f_maxmin = 1;
    2915             :                      }
    2916             :                   }
    2917             :                }
    2918           0 :                *grib_Data++ = value;
    2919             :             }
    2920             :          }
    2921             :       }
    2922             :    }
    2923           0 :    attrib->f_maxmin = f_maxmin;
    2924           0 : }
    2925             : 
    2926             : /*****************************************************************************
    2927             :  * ParseGrid() --
    2928             :  *
    2929             :  * Arthur Taylor / MDL
    2930             :  *
    2931             :  * PURPOSE
    2932             :  *   To walk through the 2 possible grids (and possible bitmap) created by
    2933             :  * UNPK_GRIB2, and combine the info into 1 grid, at the same time computing
    2934             :  * the min/max values in the grid.  It uses gridAttrib info for the missing values
    2935             :  * and it then updates the gridAttrib structure for the min/max values that it
    2936             :  * found.
    2937             :  *   It also uses scan, and ScanIndex2XY, to parse the data and organize the
    2938             :  * Grib_Data so that 0,0 is the lower left part of the grid, it then traverses
    2939             :  * the row and then moved up to the next row starting on the left.
    2940             :  *
    2941             :  * ARGUMENTS
    2942             :  *       attrib = sect 5 structure already filled in by ParseSect5 (In/Output)
    2943             :  *    Grib_Data = The place to store the grid data. (Output)
    2944             :  * grib_DataLen = The current size of Grib_Data (can increase) (Input/Output)
    2945             :  *       Nx, Ny = The dimensions of the grid (Input)
    2946             :  *         scan = How to walk through the original grid. (Input)
    2947             :  *         iain = Place to find data if it is an Integer (or float). (Input)
    2948             :  *      ibitmap = Flag stating the data has a bitmap for missing values (In)
    2949             :  *           ib = Where to find the bitmap if we have one (Input)
    2950             :  *        unitM = M in unit conversion equation y(new) = m x(orig) + b (Input)
    2951             :  *        unitB = B in unit conversion equation y(new) = m x(orig) + b (Input)
    2952             :  *    f_txtType = true if we have a valid wx/hazard type. (Input)
    2953             :  *  txt_dataLen = Length of text table
    2954             :  *  txt_f_valid = whether that entry is used/valid. (Input)
    2955             :  *    f_subGrid = True if we have a subgrid, false if not. (Input)
    2956             :  * startX stopX = The bounds of the subgrid in X. (0,-1) means full grid (In)
    2957             :  * startY stopY = The bounds of the subgrid in Y. (0,-1) means full grid (In)
    2958             :  *
    2959             :  * FILES/DATABASES: None
    2960             :  *
    2961             :  * RETURNS: void
    2962             :  *
    2963             :  * HISTORY
    2964             :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
    2965             :  *  11/2002 AAT: Added unit conversion to metaparse.c
    2966             :  *  12/2002 AAT: Optimized first loop to make it assume scan 0100 (64)
    2967             :  *         (valid 99.9%), but still have slow loop for generic case.
    2968             :  *   5/2003 AAT: Added ability to see if wxType occurs.  If so sets table
    2969             :  *          valid to 2, otherwise leaves it at 1.  If table valid is 0 then
    2970             :  *          sets value to missing value (if applicable).
    2971             :  *   7/2003 AAT: added check if f_maxmin before checking if missing was in
    2972             :  *          range of max, min for "readjust" check.
    2973             :  *   2/2004 AAT: Added startX / startY / stopX / stopY
    2974             :  *   5/2004 AAT: Found out that I used the opposite definition for bitmap
    2975             :  *          0 = missing, 1 = valid.
    2976             :  *
    2977             :  * NOTES
    2978             :  *****************************************************************************
    2979             :  */
    2980         157 : void ParseGrid (VSILFILE *fp, gridAttribType *attrib, double **Grib_Data,
    2981             :                 uInt4 *grib_DataLen, uInt4 Nx, uInt4 Ny, int scan,
    2982             :                 sInt4 nd2x3, sInt4 *iain, sInt4 ibitmap, sInt4 *ib, double unitM,
    2983             :                 double unitB, uChar f_txtType, uInt4 txt_dataLen,
    2984             :                 uChar *txt_f_valid,
    2985             :                 CPL_UNUSED uChar f_subGrid,
    2986             :                 int startX, int startY, int stopX, int stopY)
    2987             : {
    2988             :    double xmissp;       /* computed missing value needed for ibitmap = 1,
    2989             :                          * Also used if unit conversion causes confusion
    2990             :                          * over_ missing values. */
    2991             :    double xmisss;       /* Used if unit conversion causes confusion over
    2992             :                          * missing values. */
    2993             :    uChar f_readjust;    /* True if unit conversion caused confusion over
    2994             :                          * missing values. */
    2995             :    uInt4 scanIndex;     /* Where we are in the original grid. */
    2996             :    sInt4 x, y;          /* Where we are in a grid of scan value 0100 */
    2997             :    uInt4 newIndex;      /* x,y in a 1 dimensional array. */
    2998             :    double value;        /* The data in the new units. */
    2999             :    /* A pointer to Grib_Data for ease of manipulation. */
    3000         157 :    double *grib_Data = nullptr;
    3001         157 :    sInt4 missCnt = 0;   /* Number of detected missing values. */
    3002             :    uInt4 index;         /* Current index into Wx table. */
    3003         157 :    float *ain = (float *) iain;
    3004             :    uInt4 subNx;         /* The Nx dimension of the subgrid. */
    3005             :    uInt4 subNy;         /* The Ny dimension of the subgrid. */
    3006             : 
    3007         157 :    subNx = stopX - startX + 1;
    3008         157 :    subNy = stopY - startY + 1;
    3009             : 
    3010         157 :    myAssert (((!f_subGrid) && (subNx == Nx)) || (f_subGrid));
    3011         157 :    myAssert (((!f_subGrid) && (subNy == Ny)) || (f_subGrid));
    3012             : 
    3013         157 :    if( subNy == 0 || subNx > UINT_MAX / subNy )
    3014             :    {
    3015           0 :        errSprintf ("Too large raster");
    3016           0 :        *grib_DataLen = 0;
    3017           0 :        *Grib_Data = nullptr;
    3018           0 :        return;
    3019             :    }
    3020             : 
    3021         157 :    const uInt4 subNxNy = subNx * subNy;
    3022         157 :    if (subNxNy > *grib_DataLen) {
    3023             : 
    3024         157 :       if( subNxNy > 100 * 1024 * 1024 )
    3025             :       {
    3026           0 :           vsi_l_offset curPos = VSIFTellL(fp);
    3027           0 :           VSIFSeekL(fp, 0, SEEK_END);
    3028           0 :           vsi_l_offset fileSize = VSIFTellL(fp);
    3029           0 :           VSIFSeekL(fp, curPos, SEEK_SET);
    3030             :           // allow a compression ratio of 1:1000
    3031           0 :           if( subNxNy / 1000 > fileSize )
    3032             :           {
    3033           0 :             errSprintf ("ERROR: File too short\n");
    3034           0 :             *grib_DataLen = 0;
    3035           0 :             *Grib_Data = nullptr;
    3036           0 :             return;
    3037             :           }
    3038             :       }
    3039             : 
    3040         157 :       double* newData = nullptr;
    3041         157 :       const size_t nBufferSize = subNxNy * sizeof (double);
    3042             : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    3043             :       if( nBufferSize > static_cast<size_t>(INT_MAX) )
    3044             :       {
    3045             :           errSprintf ("Memory allocation failed due to being bigger than 2 GB in fuzzing mode");
    3046             :       }
    3047             :       else
    3048             : #endif
    3049         157 :       if( nBufferSize / sizeof(double) == subNxNy)
    3050             :       {
    3051         157 :         newData = (double *) realloc ((void *) (*Grib_Data), nBufferSize);
    3052             :       }
    3053         157 :       if( newData == nullptr )
    3054             :       {
    3055           0 :           errSprintf ("Memory allocation failed");
    3056           0 :           free(*Grib_Data);
    3057           0 :           *Grib_Data = nullptr;
    3058           0 :           *grib_DataLen = 0;
    3059           0 :           return;
    3060             :       }
    3061         157 :       *grib_DataLen = subNxNy;
    3062         157 :       *Grib_Data = newData;
    3063             :    }
    3064         157 :    grib_Data = *Grib_Data;
    3065             : 
    3066             :    /* Resolve possibility that the data is an integer or a float, find
    3067             :     * max/min values, and do unit conversion. (see note 1) */
    3068         157 :    if (scan == 64) {
    3069         157 :       if (attrib->f_miss == 0) {
    3070         133 :          ParseGridNoMiss (attrib, grib_Data, Nx, Ny, iain, unitM, unitB,
    3071             :                           f_txtType, txt_dataLen, txt_f_valid, startX, startY, subNx, subNy);
    3072          24 :       } else if (attrib->f_miss == 1) {
    3073          24 :          ParseGridPrimMiss (attrib, grib_Data, Nx, Ny, iain, unitM, unitB,
    3074             :                             &missCnt, f_txtType, txt_dataLen, txt_f_valid, startX, startY,
    3075             :                             subNx, subNy);
    3076           0 :       } else if (attrib->f_miss == 2) {
    3077           0 :          ParseGridSecMiss (attrib, grib_Data, Nx, Ny, iain, unitM, unitB,
    3078             :                            &missCnt, f_txtType, txt_dataLen, txt_f_valid, startX, startY, subNx,
    3079             :                            subNy);
    3080             :       }
    3081             :    } else {
    3082             :       /* Internally we use scan = 0100.  Scan is usually 0100 from the
    3083             :        * unpacker library, but if scan is not, the following code converts
    3084             :        * it.  We optimized the previous (scan 0100) case by calling a
    3085             :        * dedicated procedure.  Here we don't since for scan != 0100, we
    3086             :        * would_ need a different unpacker library, which is extremely
    3087             :        * unlikely. */
    3088           0 :       for (scanIndex = 0; scanIndex < (uInt4)nd2x3 && scanIndex < Nx * Ny; scanIndex++) {
    3089           0 :          if (attrib->fieldType) {
    3090           0 :             value = iain[scanIndex];
    3091             :          } else {
    3092           0 :             value = ain[scanIndex];
    3093             :          }
    3094             :          /* Make sure value is not a missing value when converting units, and
    3095             :           * while computing max/min. */
    3096           0 :          if ((attrib->f_miss == 0) ||
    3097           0 :              ((attrib->f_miss == 1) && (value != attrib->missPri)) ||
    3098           0 :              ((attrib->f_miss == 2) && (value != attrib->missPri) &&
    3099           0 :               (value != attrib->missSec))) {
    3100             :             /* Convert the units. */
    3101           0 :             if (unitM == -10) {
    3102           0 :                value = pow (10.0, value);
    3103             :             } else {
    3104           0 :                value = unitM * value + unitB;
    3105             :             }
    3106             :             /* Don't have to check if value became missing value, because we
    3107             :              * can check if missing falls in the range of min/max.  If
    3108             :              * missing does fall in that range we need to move missing. See
    3109             :              * f_readjust */
    3110           0 :             if (f_txtType) {
    3111           0 :                index = (uInt4) value;
    3112           0 :                if (index < txt_dataLen) {
    3113           0 :                   if (txt_f_valid[index] == 1) {
    3114           0 :                      txt_f_valid[index] = 2;
    3115           0 :                   } else if (txt_f_valid[index] == 0) {
    3116             :                      /* Table is not valid here so set value to missPri */
    3117           0 :                      if (attrib->f_miss != 0) {
    3118           0 :                         value = attrib->missPri;
    3119           0 :                         missCnt++;
    3120             :                      } else {
    3121             :                         /* No missing value, so use index = WxType->dataLen */
    3122             :                         /* No... set f_valid to 3 so we know we used this
    3123             :                          * invalid element, then handle it in degrib2.c ::
    3124             :                          * ReadGrib2Record() where we set it back to 0. */
    3125           0 :                         txt_f_valid[index] = 3;
    3126             :                      }
    3127             :                   }
    3128             :                }
    3129             :             }
    3130           0 :             if ((!f_txtType) ||
    3131           0 :                 ((attrib->f_miss == 0) || (value != attrib->missPri))) {
    3132           0 :                if (attrib->f_maxmin) {
    3133           0 :                   if (value < attrib->min) {
    3134           0 :                      attrib->min = value;
    3135           0 :                   } else if (value > attrib->max) {
    3136           0 :                      attrib->max = value;
    3137             :                   }
    3138             :                } else {
    3139           0 :                   attrib->min = attrib->max = value;
    3140           0 :                   attrib->f_maxmin = 1;
    3141             :                }
    3142             :             }
    3143             :          } else {
    3144           0 :             missCnt++;
    3145             :          }
    3146           0 :          ScanIndex2XY (scanIndex, &x, &y, scan, Nx, Ny);
    3147             :          /* ScanIndex returns value as if scan was 0100 */
    3148           0 :          newIndex = (uInt4)(x - 1) + (uInt4)(y - 1) * Nx;
    3149           0 :          grib_Data[newIndex] = value;
    3150             :       }
    3151             :    }
    3152             : 
    3153             :    /* Deal with possibility that unit conversion ended up with valid numbers
    3154             :     * being interpreted as missing. */
    3155         157 :    f_readjust = 0;
    3156         157 :    xmissp = attrib->missPri;
    3157         157 :    xmisss = attrib->missSec;
    3158         157 :    if (attrib->f_maxmin) {
    3159         154 :       if ((attrib->f_miss == 1) || (attrib->f_miss == 2)) {
    3160          21 :          if ((attrib->missPri >= attrib->min) &&
    3161          21 :              (attrib->missPri <= attrib->max)) {
    3162           0 :             xmissp = attrib->max + 1;
    3163           0 :             f_readjust = 1;
    3164             :          }
    3165          21 :          if (attrib->f_miss == 2) {
    3166           0 :             if ((attrib->missSec >= attrib->min) &&
    3167           0 :                 (attrib->missSec <= attrib->max)) {
    3168           0 :                xmisss = attrib->max + 2;
    3169           0 :                f_readjust = 1;
    3170             :             }
    3171             :          }
    3172             :       }
    3173             :    }
    3174             : 
    3175             :    /* Walk through the grid, resetting the missing values, as determined by
    3176             :     * the original grid. */
    3177         157 :    if (f_readjust) {
    3178           0 :       for (scanIndex = 0; scanIndex < (uInt4)nd2x3 && scanIndex < Nx * Ny; scanIndex++) {
    3179           0 :          ScanIndex2XY (scanIndex, &x, &y, scan, Nx, Ny);
    3180             :          /* ScanIndex returns value as if scan was 0100 */
    3181           0 :          newIndex = (uInt4)(x - 1) + (uInt4)(y - 1) * Nx;
    3182           0 :          if (attrib->fieldType) {
    3183           0 :             value = iain[scanIndex];
    3184             :          } else {
    3185           0 :             value = ain[scanIndex];
    3186             :          }
    3187           0 :          if (value == attrib->missPri) {
    3188           0 :             grib_Data[newIndex] = xmissp;
    3189           0 :          } else if ((attrib->f_miss == 2) && (value == attrib->missSec)) {
    3190           0 :             grib_Data[newIndex] = xmisss;
    3191             :          }
    3192             :       }
    3193           0 :       attrib->missPri = xmissp;
    3194           0 :       if (attrib->f_miss == 2) {
    3195           0 :          attrib->missSec = xmisss;
    3196             :       }
    3197             :    }
    3198             : 
    3199             :    /* Resolve bitmap (if there is one) in the data. */
    3200         157 :    if (ibitmap) {
    3201           2 :       attrib->f_maxmin = 0;
    3202           2 :       if ((attrib->f_miss != 1) && (attrib->f_miss != 2)) {
    3203           2 :          missCnt = 0;
    3204             :          /* Figure out a missing value. */
    3205           2 :          xmissp = 9999;
    3206             : #ifdef unreachable
    3207             :          if (attrib->f_maxmin) {
    3208             :             if ((xmissp <= attrib->max) && (xmissp >= attrib->min)) {
    3209             :                xmissp = attrib->max + 1;
    3210             :             }
    3211             :          }
    3212             : #endif
    3213             :          /* embed the missing value. */
    3214         802 :          for (scanIndex = 0; scanIndex < (uInt4)nd2x3 && scanIndex < Nx * Ny; scanIndex++) {
    3215         800 :             ScanIndex2XY (scanIndex, &x, &y, scan, Nx, Ny);
    3216             :             /* ScanIndex returns value as if scan was 0100 */
    3217         800 :             newIndex = (uInt4)(x - 1) + (uInt4)(y - 1) * Nx;
    3218             :             /* Corrected this on 5/10/2004 */
    3219         800 :             if (ib[scanIndex] != 1) {
    3220           0 :                grib_Data[newIndex] = xmissp;
    3221           0 :                missCnt++;
    3222             :             } else {
    3223         800 :                if (!attrib->f_maxmin) {
    3224           2 :                   attrib->f_maxmin = 1;
    3225           2 :                   attrib->max = attrib->min = grib_Data[newIndex];
    3226             :                } else {
    3227         798 :                   if (attrib->max < grib_Data[newIndex])
    3228           9 :                      attrib->max = grib_Data[newIndex];
    3229         798 :                   if (attrib->min > grib_Data[newIndex])
    3230           9 :                      attrib->min = grib_Data[newIndex];
    3231             :                }
    3232             :             }
    3233             :          }
    3234           2 :          attrib->f_miss = 1;
    3235           2 :          attrib->missPri = xmissp;
    3236             :       }
    3237           2 :       if (!attrib->f_maxmin) {
    3238           0 :          attrib->f_maxmin = 1;
    3239           0 :          attrib->max = attrib->min = xmissp;
    3240             :       }
    3241             :    }
    3242         157 :    attrib->numMiss = missCnt;
    3243             : }
    3244             : 
    3245             : #ifdef unused_by_GDAL
    3246             : typedef struct {
    3247             :    double value;
    3248             :    int cnt;
    3249             : } freqType;
    3250             : 
    3251             : static int freqCompare (const void *A, const void *B)
    3252             : {
    3253             :    const freqType *a = (freqType *) A;
    3254             :    const freqType *b = (freqType *) B;
    3255             : 
    3256             :    if (a->value < b->value)
    3257             :       return -1;
    3258             :    if (a->value > b->value)
    3259             :       return 1;
    3260             :    return 0;
    3261             : }
    3262             : 
    3263             : void FreqPrint (char **ans, double *Data, sInt4 DataLen, sInt4 Nx,
    3264             :                 sInt4 Ny, sChar decimal, char *comment)
    3265             : {
    3266             :    int x, y, i;
    3267             :    double *ptr = NULL;
    3268             :    double value;
    3269             :    freqType *freq = NULL;
    3270             :    int numFreq = 0;
    3271             :    char format[20];
    3272             : 
    3273             :    myAssert (*ans == NULL);
    3274             : 
    3275             :    if ((Nx < 0) || (Ny < 0) || (Nx * Ny > DataLen)) {
    3276             :       return;
    3277             :    }
    3278             : 
    3279             :    ptr = Data;
    3280             :    for (y = 0; y < Ny; y++) {
    3281             :       for (x = 0; x < Nx; x++) {
    3282             :          /* 2/28/2006 Introduced value to round before putting the data in
    3283             :           * the Freq table. */
    3284             :          value = myRound (*ptr, decimal);
    3285             :          for (i = 0; i < numFreq; i++) {
    3286             :             if (value == freq[i].value) {
    3287             :                freq[i].cnt++;
    3288             :                break;
    3289             :             }
    3290             :          }
    3291             :          if (i == numFreq) {
    3292             :             numFreq++;
    3293             :             freq = (freqType *) realloc (freq, numFreq * sizeof (freqType));
    3294             :             freq[i].value = value;
    3295             :             freq[i].cnt = 1;
    3296             :          }
    3297             :          ptr++;
    3298             :       }
    3299             :    }
    3300             : 
    3301             :    if( freq )
    3302             :      qsort (freq, numFreq, sizeof (freq[0]), freqCompare);
    3303             : 
    3304             :    mallocSprintf (ans, "%s | count\n", comment);
    3305             :    snprintf (format, sizeof(format), "%%.%df | %%d\n", decimal);
    3306             :    for (i = 0; i < numFreq; i++) {
    3307             :       reallocSprintf (ans, format, myRound (freq[i].value, decimal),
    3308             :                       freq[i].cnt);
    3309             :    }
    3310             :    free (freq);
    3311             : }
    3312             : #endif

Generated by: LCOV version 1.14