1 /*****************************************************************************
2  * degrib1.c
3  *
4  * DESCRIPTION
5  *    This file contains the main driver routines to unpack GRIB 1 files.
6  *
7  * HISTORY
8  *   4/2003 Arthur Taylor (MDL / RSIS): Created.
9  *
10  * NOTES
11  *   GRIB 1 files are assumed to be big endian.
12  *****************************************************************************
13  */
14 
15 #include <assert.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <math.h>
20 
21 #include <limits>
22 
23 #include "degrib2.h"
24 #include "myerror.h"
25 #include "myassert.h"
26 #include "tendian.h"
27 #include "scan.h"
28 #include "degrib1.h"
29 #include "metaname.h"
30 #include "clock.h"
31 #include "cpl_error.h"
32 #include "cpl_string.h"
33 
34 /* default missing data value (see: bitmap GRIB1: sect3 and sect4) */
35 /* UNDEFINED is default, UNDEFINED_PRIM is desired choice. */
36 #define UNDEFINED 9.999e20
37 #define UNDEFINED_PRIM 9999
38 
39 #define GRIB_UNSIGN_INT3(a,b,c) ((a<<16)+(b<<8)+c)
40 #define GRIB_UNSIGN_INT2(a,b) ((a<<8)+b)
41 #define GRIB_SIGN_INT3(a,b,c) ((1-(int) ((unsigned) (a & 0x80) >> 6)) * (int) (((a & 127) << 16)+(b<<8)+c))
42 #define GRIB_SIGN_INT2(a,b) ((1-(int) ((unsigned) (a & 0x80) >> 6)) * (int) (((a & 0x7f) << 8) + b))
43 
44 /* various centers */
45 #define NMC	7
46 #define US_OTHER 9
47 #define CPTEC 46
48 /* Canada Center */
49 #define CMC	54
50 #define AFWA 57
51 #define DWD 78
52 #define ECMWF 98
53 #define ATHENS 96
54 #define NORWAY 88
55 
56 /* various subcenters */
57 #define SUBCENTER_MDL 14
58 #define SUBCENTER_TDL 11
59 
60 /* The idea of rean or opn is to give a warning about default choice of
61    which table to use. */
62 #define DEF_NCEP_TABLE rean_nowarn
63 enum Def_NCEP_Table { rean, opn, rean_nowarn, opn_nowarn };
64 
65 #if 0 // moved by GDAL in degrib1.h
66 
67 /* For an update to these tables see:
68  * http://www.nco.ncep.noaa.gov/pmb/docs/on388/table2.html
69  */
70 
71 extern GRIB1ParmTable parm_table_ncep_opn[256];
72 extern GRIB1ParmTable parm_table_ncep_reanal[256];
73 extern GRIB1ParmTable parm_table_ncep_tdl[256];
74 extern GRIB1ParmTable parm_table_ncep_mdl[256];
75 extern GRIB1ParmTable parm_table_omb[256];
76 extern GRIB1ParmTable parm_table_nceptab_129[256];
77 extern GRIB1ParmTable parm_table_nceptab_130[256];
78 extern GRIB1ParmTable parm_table_nceptab_131[256];
79 extern GRIB1ParmTable parm_table_nceptab_133[256];
80 extern GRIB1ParmTable parm_table_nceptab_140[256];
81 extern GRIB1ParmTable parm_table_nceptab_141[256];
82 
83 extern GRIB1ParmTable parm_table_nohrsc[256];
84 
85 extern GRIB1ParmTable parm_table_cptec_254[256];
86 
87 extern GRIB1ParmTable parm_table_afwa_000[256];
88 extern GRIB1ParmTable parm_table_afwa_001[256];
89 extern GRIB1ParmTable parm_table_afwa_002[256];
90 extern GRIB1ParmTable parm_table_afwa_003[256];
91 extern GRIB1ParmTable parm_table_afwa_010[256];
92 extern GRIB1ParmTable parm_table_afwa_011[256];
93 
94 extern GRIB1ParmTable parm_table_dwd_002[256];
95 extern GRIB1ParmTable parm_table_dwd_201[256];
96 extern GRIB1ParmTable parm_table_dwd_202[256];
97 extern GRIB1ParmTable parm_table_dwd_203[256];
98 
99 extern GRIB1ParmTable parm_table_ecmwf_128[256];
100 extern GRIB1ParmTable parm_table_ecmwf_129[256];
101 extern GRIB1ParmTable parm_table_ecmwf_130[256];
102 extern GRIB1ParmTable parm_table_ecmwf_131[256];
103 extern GRIB1ParmTable parm_table_ecmwf_140[256];
104 extern GRIB1ParmTable parm_table_ecmwf_150[256];
105 extern GRIB1ParmTable parm_table_ecmwf_160[256];
106 extern GRIB1ParmTable parm_table_ecmwf_170[256];
107 extern GRIB1ParmTable parm_table_ecmwf_180[256];
108 
109 extern GRIB1ParmTable parm_table_athens[256];
110 
111 extern GRIB1ParmTable parm_table_norway128[256];
112 
113 extern GRIB1ParmTable parm_table_cmc[256];
114 
115 extern GRIB1ParmTable parm_table_undefined[256];
116 
117 #endif
118 
119 /*****************************************************************************
120  * Choose_ParmTable() --
121  *
122  * Arthur Taylor / MDL
123  *
124  * PURPOSE
125  *   Chooses the correct Parameter table depending on what is in the GRIB1
126  * message's "Product Definition Section".
127  *
128  * ARGUMENTS
129  *   pdsMeta = The filled out pdsMeta data structure to base choice on. (Input)
130  *    center = The Center that created the data (Input)
131  * subcenter = The Sub Center that created the data (Input)
132  *
133  * FILES/DATABASES: None
134  *
135  * RETURNS: ParmTable (appropriate parameter table.)
136  *
137  * HISTORY
138  *   <unknown> : wgrib library : cnames.c
139  *   4/2003 Arthur Taylor (MDL/RSIS): Modified
140  *  10/2005 AAT: Adjusted to take center, subcenter
141  *
142  * NOTES
143  *****************************************************************************
144  */
Choose_ParmTable(pdsG1Type * pdsMeta,unsigned short int center,unsigned short int subcenter)145 static const GRIB1ParmTable *Choose_ParmTable (pdsG1Type *pdsMeta,
146                                          unsigned short int center,
147                                          unsigned short int subcenter)
148 {
149    int process;         /* The process ID from the GRIB1 message. */
150 
151    switch (center) {
152       case NMC:
153          if (pdsMeta->mstrVersion <= 3) {
154             switch (subcenter) {
155                case 1:
156                   return &parm_table_ncep_reanal[0];
157                case SUBCENTER_TDL:
158                   return &parm_table_ncep_tdl[0];
159                case SUBCENTER_MDL:
160                   return &parm_table_ncep_mdl[0];
161             }
162          }
163          /* figure out if NCEP opn or reanalysis */
164          switch (pdsMeta->mstrVersion) {
165             case 0:
166                return &parm_table_ncep_opn[0];
167             case 1:
168             case 2:
169                process = pdsMeta->genProcess;
170                if ((subcenter != 0) || ((process != 80) && (process != 180))) {
171                   return &parm_table_ncep_opn[0];
172                }
173 #if 0
174                /* At this point could be either the opn or reanalysis table */
175                switch (DEF_NCEP_TABLE) {
176                   case opn_nowarn:
177                      return &parm_table_ncep_opn[0];
178                   case rean_nowarn:
179                      return &parm_table_ncep_reanal[0];
180                }
181                break;
182 #else
183                // ERO: this is the non convoluted version of the above code
184                return &parm_table_ncep_reanal[0];
185 #endif
186             case 3:
187                return &parm_table_ncep_opn[0];
188             case 128:
189                return &parm_table_omb[0];
190             case 129:
191                return &parm_table_nceptab_129[0];
192             case 130:
193                return &parm_table_nceptab_130[0];
194             case 131:
195                return &parm_table_nceptab_131[0];
196             case 133:
197                return &parm_table_nceptab_133[0];
198             case 140:
199                return &parm_table_nceptab_140[0];
200             case 141:
201                return &parm_table_nceptab_141[0];
202          }
203          break;
204       case AFWA:
205          switch (subcenter) {
206             case 0:
207                return &parm_table_afwa_000[0];
208             case 1:
209             case 4:
210                return &parm_table_afwa_001[0];
211             case 2:
212                return &parm_table_afwa_002[0];
213             case 3:
214                return &parm_table_afwa_003[0];
215             case 10:
216                return &parm_table_afwa_010[0];
217             case 11:
218                return &parm_table_afwa_011[0];
219 /*            case 5:*/
220                /* Didn't have a table 5. */
221          }
222          break;
223       case ECMWF:
224          switch (pdsMeta->mstrVersion) {
225             case 128:
226                return &parm_table_ecmwf_128[0];
227             case 129:
228                return &parm_table_ecmwf_129[0];
229             case 130:
230                return &parm_table_ecmwf_130[0];
231             case 131:
232                return &parm_table_ecmwf_131[0];
233             case 140:
234                return &parm_table_ecmwf_140[0];
235             case 150:
236                return &parm_table_ecmwf_150[0];
237             case 160:
238                return &parm_table_ecmwf_160[0];
239             case 170:
240                return &parm_table_ecmwf_170[0];
241             case 180:
242                return &parm_table_ecmwf_180[0];
243             case 228:
244                return &parm_table_ecmwf_228[0];
245          }
246          break;
247       case DWD:
248          switch (pdsMeta->mstrVersion) {
249             case 2:
250                return &parm_table_dwd_002[0];
251             case 201:
252                return &parm_table_dwd_201[0];
253             case 202:
254                return &parm_table_dwd_202[0];
255             case 203:
256                return &parm_table_dwd_203[0];
257          }
258          break;
259       case CPTEC:
260          switch (pdsMeta->mstrVersion) {
261             case 254:
262                return &parm_table_cptec_254[0];
263          }
264          break;
265       case US_OTHER:
266          switch (subcenter) {
267             case 163:
268                return &parm_table_nohrsc[0];
269             /* Based on 11/7/2006 email with Rob Doornbos, mimic'd what wgrib
270              * did which was to use parm_table_ncep_opn. */
271             case 161:
272                return &parm_table_ncep_opn[0];
273          }
274          break;
275       case ATHENS:
276          return &parm_table_athens[0];
277          break;
278       case NORWAY:
279          if (pdsMeta->mstrVersion == 128) {
280             return &parm_table_norway128[0];
281          }
282          break;
283       case CMC:
284          return &parm_table_cmc[0];
285          break;
286    }
287    if (pdsMeta->mstrVersion > 3) {
288       CPLError( CE_Warning, CPLE_AppDefined, "GRIB: Don't understand the parameter table, since center %d-%d used\n"
289               "parameter table version %d instead of 3 (international exchange).\n"
290               "Using default for now (which might lead to erroneous interpretation), but please email arthur.taylor@noaa.gov\n"
291               "about adding this table to his 'degrib1.c' and 'grib1tab.c' files.",
292               center, subcenter, pdsMeta->mstrVersion);
293    }
294    if (pdsMeta->cat > 127) {
295       CPLError(CE_Warning, CPLE_AppDefined, "GRIB: Parameter %d is > 127, so it falls in the local use section of\n"
296               "the parameter table (and is undefined on the international table.\n"
297               "Using default for now(which might lead to erroneous interpretation), but please email arthur.taylor@noaa.gov\n"
298               "about adding this table to his 'degrib1.c' and 'grib1tab.c' files.",
299               pdsMeta->cat);
300    }
301    return &parm_table_undefined[0];
302 }
303 
304 /*****************************************************************************
305  * GRIB1_Table2LookUp() --
306  *
307  * Arthur Taylor / MDL
308  *
309  * PURPOSE
310  *   Returns the variable name (type of data) and comment (longer form of the
311  * name) for the data that is in the GRIB1 message.
312  *
313  * ARGUMENTS
314  *      name = A pointer to the resulting short name. (Output)
315  *   comment = A pointer to the resulting long name. (Output)
316  *   pdsMeta = The filled out pdsMeta data structure to base choice on. (Input)
317  *    center = The Center that created the data (Input)
318  * subcenter = The Sub Center that created the data (Input)
319  *
320  * FILES/DATABASES: None
321  *
322  * RETURNS: void
323  *
324  * HISTORY
325  *   4/2003 Arthur Taylor (MDL/RSIS): Created
326  *  10/2005 AAT: Adjusted to take center, subcenter
327  *
328  * NOTES
329  *****************************************************************************
330  */
GRIB1_Table2LookUp(pdsG1Type * pdsMeta,const char ** name,const char ** comment,const char ** unit,int * convert,unsigned short int center,unsigned short int subcenter)331 static void GRIB1_Table2LookUp (pdsG1Type *pdsMeta, const char **name,
332                                 const char **comment, const char **unit,
333                                 int *convert,
334                                 unsigned short int center,
335                                 unsigned short int subcenter)
336 {
337    const GRIB1ParmTable *table; /* The parameter table chosen by the pdsMeta data */
338 
339    table = Choose_ParmTable (pdsMeta, center, subcenter);
340    if ((center == NMC) && (pdsMeta->mstrVersion == 129)
341        && (pdsMeta->cat == 180)) {
342       if (pdsMeta->timeRange == 3) {
343          *name = "AVGOZCON";
344          *comment = "Average Ozone Concentration";
345          *unit = "PPB";
346          *convert = UC_NONE;
347          return;
348       }
349    }
350    *name = table[pdsMeta->cat].name;
351    if( strcmp(*name, CPLSPrintf("var%d", pdsMeta->cat)) == 0 )
352    {
353        if( center == ECMWF )
354            *name = CPLSPrintf("var%d of table %d of center ECMWF", pdsMeta->cat, pdsMeta->mstrVersion);
355        else
356            *name = CPLSPrintf("var%d of table %d of center %d", pdsMeta->cat, pdsMeta->mstrVersion, center);
357    }
358    *comment = table[pdsMeta->cat].comment;
359    *unit = table[pdsMeta->cat].unit;
360    *convert = table[pdsMeta->cat].convert;
361 /*   printf ("%s %s %s\n", *name, *comment, *unit);*/
362 }
363 
364 /* Similar to metaname.c :: ParseLevelName() */
GRIB1_Table3LookUp(pdsG1Type * pdsMeta,char ** shortLevelName,char ** longLevelName)365 static void GRIB1_Table3LookUp (pdsG1Type *pdsMeta, char **shortLevelName,
366                                 char **longLevelName)
367 {
368    uChar type = pdsMeta->levelType;
369    uChar level1, level2;
370 
371    free (*shortLevelName);
372    *shortLevelName = nullptr;
373    free (*longLevelName);
374    *longLevelName = nullptr;
375    /* Find out if val is a 2 part value or not */
376    if (GRIB1Surface[type].f_twoPart) {
377       level1 = (pdsMeta->levelVal >> 8);
378       level2 = (pdsMeta->levelVal & 0xff);
379       reallocSprintf (shortLevelName, "%d-%d-%s", level1, level2,
380                       GRIB1Surface[type].name);
381       reallocSprintf (longLevelName, "%d-%d[%s] %s (%s)", level1, level2,
382                       GRIB1Surface[type].unit, GRIB1Surface[type].name,
383                       GRIB1Surface[type].comment);
384    } else {
385       reallocSprintf (shortLevelName, "%d-%s", pdsMeta->levelVal,
386                       GRIB1Surface[type].name);
387       reallocSprintf (longLevelName, "%d[%s] %s (%s)", pdsMeta->levelVal,
388                       GRIB1Surface[type].unit, GRIB1Surface[type].name,
389                       GRIB1Surface[type].comment);
390    }
391 }
392 
393 /*****************************************************************************
394  * fval_360() --
395  *
396  * Albion Taylor / ARL
397  *
398  * PURPOSE
399  *   Converts an IBM360 floating point number to an IEEE floating point
400  * number.  The IBM floating point spec represents the fraction as the last
401  * 3 bytes of the number, with 0xffffff being just shy of 1.0.  The first byte
402  * leads with a sign bit, and the last seven bits represent the powers of 16
403  * (not 2), with a bias of 0x40 giving 16^0.
404  *
405  * ARGUMENTS
406  * aval = A sInt4 containing the original IBM 360 number. (Input)
407  *
408  * FILES/DATABASES: None
409  *
410  * RETURNS: double = the value that aval represents.
411  *
412  * HISTORY
413  *   <unknown> Albion Taylor (ARL): Created
414  *   4/2003 Arthur Taylor (MDL/RSIS): Cleaned up.
415  *   5/2003 AAT: some kind of Bug due to optimizations...
416  *          -1055916032 => 0 instead of -1
417  *
418  * NOTES
419  *****************************************************************************
420  */
fval_360(uInt4 aval)421 static double fval_360 (uInt4 aval)
422 {
423    short int ptr[4];
424 #ifdef LITTLE_ENDIAN
425    ptr[3] = ((((aval >> 24) & 0x7f) << 2) + (0x3ff - 0x100)) << 4;
426    ptr[2] = 0;
427    ptr[1] = 0;
428    ptr[0] = 0;
429 #else
430    ptr[0] = ((((aval >> 24) & 0x7f) << 2) + (0x3ff - 0x100)) << 4;
431    ptr[1] = 0;
432    ptr[2] = 0;
433    ptr[3] = 0;
434 #endif
435    double pow16;
436    memcpy(&pow16, ptr, 8);
437    return ((aval & 0x80000000) ? -pow16 : pow16) *
438          (aval & 0xffffff) / ((double) 0x1000000);
439 }
440 
441 /*****************************************************************************
442  * ReadGrib1Sect1() --
443  *
444  * Arthur Taylor / MDL
445  *
446  * PURPOSE
447  *   Parses the GRIB1 "Product Definition Section" or section 1, filling out
448  * the pdsMeta data structure.
449  *
450  * ARGUMENTS
451  *       pds = The compressed part of the message dealing with "PDS". (Input)
452  *    pdsLen = Size of pds in bytes. (Input)
453  *   gribLen = The total length of the GRIB1 message. (Input)
454  *    curLoc = Current location in the GRIB1 message. (Output)
455  *   pdsMeta = The filled out pdsMeta data structure. (Output)
456  *     f_gds = boolean if there is a Grid Definition Section. (Output)
457  *    gridID = The Grid ID. (Output)
458  *     f_bms = boolean if there is a Bitmap Section. (Output)
459  *       DSF = Decimal Scale Factor for unpacking the data. (Output)
460  *    center = The Center that created the data (Output)
461  * subcenter = The Sub Center that created the data (Output)
462  *
463  * FILES/DATABASES: None
464  *
465  * RETURNS: int (could use errSprintf())
466  *  0 = OK
467  * -1 = gribLen is too small.
468  *
469  * HISTORY
470  *   4/2003 Arthur Taylor (MDL/RSIS): Created.
471  *   5/2004 AAT: Paid attention to table 5 (Time range indicator) and which of
472  *          P1 and P2 are the valid times.
473  *  10/2005 AAT: Adjusted to take center, subcenter
474  *
475  * NOTES
476  *****************************************************************************
477  */
ReadGrib1Sect1(uChar * pds,uInt4 pdsLen,uInt4 gribLen,uInt4 * curLoc,pdsG1Type * pdsMeta,char * f_gds,uChar * gridID,char * f_bms,short int * DSF,unsigned short int * center,unsigned short int * subcenter)478 static int ReadGrib1Sect1 (uChar *pds, uInt4 pdsLen, uInt4 gribLen, uInt4 *curLoc,
479                            pdsG1Type *pdsMeta, char *f_gds, uChar *gridID,
480                            char *f_bms, short int *DSF,
481                            unsigned short int *center,
482                            unsigned short int *subcenter)
483 {
484    uInt4 sectLen;       /* Length in bytes of the current section. */
485    int year;            /* The year of the GRIB1 Message. */
486    double P1_DeltaTime; /* Used to parse the time for P1 */
487    double P2_DeltaTime; /* Used to parse the time for P2 */
488    uInt4 uli_temp;
489 #ifdef DEBUG
490 /*
491    int i;
492 */
493 #endif
494    /* We will read the first required 28 bytes */
495    if( pdsLen < 28 )
496        return -1;
497 
498    sectLen = GRIB_UNSIGN_INT3 (*pds, pds[1], pds[2]);
499    if( sectLen > pdsLen )
500        return -1;
501 #ifdef DEBUG
502 /*
503    printf ("Section 1 length = %ld\n", sectLen);
504    for (i = 0; i < sectLen; i++) {
505       printf ("Sect1: item %d = %d\n", i + 1, pds[i]);
506    }
507    printf ("Century is item 25\n");
508 */
509 #endif
510    *curLoc += sectLen;
511    if (*curLoc > gribLen) {
512       errSprintf ("Ran out of data in PDS (GRIB 1 Section 1)\n");
513       return -1;
514    }
515    pds += 3;
516    pdsMeta->mstrVersion = *(pds++);
517    *center = *(pds++);
518    pdsMeta->genProcess = *(pds++);
519    *gridID = *(pds++);
520    *f_gds = GRIB2BIT_1 & *pds;
521    *f_bms = GRIB2BIT_2 & *pds;
522    pds++;
523    pdsMeta->cat = *(pds++);
524    pdsMeta->levelType = *(pds++);
525    pdsMeta->levelVal = GRIB_UNSIGN_INT2 (*pds, pds[1]);
526    pds += 2;
527    if (*pds == 0) {
528       /* The 12 is because we have increased pds by 12. (but 25 is in
529        * reference of 1..25, so we need another -1) */
530       year = (pds[25 - 13] * 100);
531    } else {
532       /* The 12 is because we have increased pds by 12. (but 25 is in
533        * reference of 1..25, so we need another -1) */
534       year = *pds + ((pds[25 - 13] - 1) * 100);
535    }
536 
537    if (ParseTime (&(pdsMeta->refTime), year, pds[1], pds[2], pds[3], pds[4],
538                   0) != 0) {
539       preErrSprintf ("Error In call to ParseTime\n");
540       errSprintf ("(Probably a corrupt file)\n");
541       return -1;
542    }
543    pds += 5;
544    pdsMeta->timeRange = pds[3];
545    if (ParseSect4Time2secV1 (pds[1], *pds, &P1_DeltaTime) == 0) {
546       pdsMeta->P1 = pdsMeta->refTime + P1_DeltaTime;
547    } else {
548       pdsMeta->P1 = pdsMeta->refTime;
549       printf ("Warning! : Can't figure out time unit of %u\n", *pds);
550    }
551    if (ParseSect4Time2secV1 (pds[2], *pds, &P2_DeltaTime) == 0) {
552       pdsMeta->P2 = pdsMeta->refTime + P2_DeltaTime;
553    } else {
554       pdsMeta->P2 = pdsMeta->refTime;
555       printf ("Warning! : Can't figure out time unit of %u\n", *pds);
556    }
557    /* The following is based on Table 5. */
558    /* Note: For ensemble forecasts, 119 has meaning. */
559    switch (pdsMeta->timeRange) {
560       case 0:
561       case 1:
562       case 113:
563       case 114:
564       case 115:
565       case 116:
566       case 117:
567       case 118:
568       case 123:
569       case 124:
570          pdsMeta->validTime = pdsMeta->P1;
571          break;
572       case 2:
573          /* Puzzling case. */
574          pdsMeta->validTime = pdsMeta->P2;
575          break;
576       case 3:
577       case 4:
578       case 5:
579       case 51:
580          pdsMeta->validTime = pdsMeta->P2;
581          break;
582       case 10:
583          if (ParseSect4Time2secV1 (GRIB_UNSIGN_INT2 (pds[1], pds[2]), *pds,
584                                    &P1_DeltaTime) == 0) {
585             pdsMeta->P2 = pdsMeta->P1 = pdsMeta->refTime + P1_DeltaTime;
586          } else {
587             pdsMeta->P2 = pdsMeta->P1 = pdsMeta->refTime;
588             printf ("Warning! : Can't figure out time unit of %u\n", *pds);
589          }
590          pdsMeta->validTime = pdsMeta->P1;
591          break;
592       default:
593          pdsMeta->validTime = pdsMeta->P1;
594    }
595    pds += 4;
596    pdsMeta->Average = GRIB_UNSIGN_INT2 (*pds, pds[1]);
597    pds += 2;
598    pdsMeta->numberMissing = *(pds++);
599    /* Skip over centry of reference time. */
600    pds++;
601    *subcenter = *(pds++);
602    *DSF = GRIB_SIGN_INT2 (*pds, pds[1]);
603    pds += 2;
604    pdsMeta->f_hasEns = 0;
605    pdsMeta->f_hasProb = 0;
606    pdsMeta->f_hasCluster = 0;
607    if (sectLen < 41) {
608       return 0;
609    }
610    /* Following is based on:
611     * http://www.emc.ncep.noaa.gov/gmb/ens/info/ens_grib.html */
612    if ((*center == NMC) && (*subcenter == 2)) {
613       if (sectLen < 45) {
614          printf ("Warning! Problems with Ensemble section\n");
615          return 0;
616       }
617       pdsMeta->f_hasEns = 1;
618       pdsMeta->ens.BitFlag = *(pds++);
619 /*      octet21 = pdsMeta->timeRange; = 119 has meaning now */
620       pds += 11;
621       pdsMeta->ens.Application = *(pds++);
622       pdsMeta->ens.Type = *(pds++);
623       pdsMeta->ens.Number = *(pds++);
624       pdsMeta->ens.ProdID = *(pds++);
625       pdsMeta->ens.Smooth = *(pds++);
626       if ((pdsMeta->cat == 191) || (pdsMeta->cat == 192) ||
627           (pdsMeta->cat == 193)) {
628          if (sectLen < 60) {
629             printf ("Warning! Problems with Ensemble Probability section\n");
630             return 0;
631          }
632          pdsMeta->f_hasProb = 1;
633          pdsMeta->prob.Cat = pdsMeta->cat;
634          pdsMeta->cat = *(pds++);
635          pdsMeta->prob.Type = *(pds++);
636          MEMCPY_BIG (&uli_temp, pds, sizeof (sInt4));
637          pdsMeta->prob.lower = fval_360 (uli_temp);
638          pds += 4;
639          MEMCPY_BIG (&uli_temp, pds, sizeof (sInt4));
640          pdsMeta->prob.upper = fval_360 (uli_temp);
641          pds += 4;
642          pds += 4;
643       }
644       if ((pdsMeta->ens.Type == 4) || (pdsMeta->ens.Type == 5)) {
645          /* 87 ... 100 was reserved, but may not be encoded */
646          if ((sectLen < 100) && (sectLen != 86)) {
647             printf ("Warning! Problems with Ensemble Clustering section\n");
648             printf ("Section length == %u\n", sectLen);
649             return 0;
650          }
651          if (pdsMeta->f_hasProb == 0) {
652             pds += 14;
653          }
654          pdsMeta->f_hasCluster = 1;
655          pdsMeta->cluster.ensSize = *(pds++);
656          pdsMeta->cluster.clusterSize = *(pds++);
657          pdsMeta->cluster.Num = *(pds++);
658          pdsMeta->cluster.Method = *(pds++);
659          pdsMeta->cluster.NorLat = GRIB_UNSIGN_INT3 (*pds, pds[1], pds[2]);
660          pdsMeta->cluster.NorLat = pdsMeta->cluster.NorLat / 1000.;
661          pds += 3;
662          pdsMeta->cluster.SouLat = GRIB_UNSIGN_INT3 (*pds, pds[1], pds[2]);
663          pdsMeta->cluster.SouLat = pdsMeta->cluster.SouLat / 1000.;
664          pds += 3;
665          pdsMeta->cluster.EasLon = GRIB_UNSIGN_INT3 (*pds, pds[1], pds[2]);
666          pdsMeta->cluster.EasLon = pdsMeta->cluster.EasLon / 1000.;
667          pds += 3;
668          pdsMeta->cluster.WesLon = GRIB_UNSIGN_INT3 (*pds, pds[1], pds[2]);
669          pdsMeta->cluster.WesLon = pdsMeta->cluster.WesLon / 1000.;
670          pds += 3;
671          memcpy (pdsMeta->cluster.Member, pds, 10);
672          pdsMeta->cluster.Member[10] = '\0';
673       }
674       /* Following based on:
675        * http://www.ecmwf.int/publications/manuals/libraries/gribex/
676        * localGRIBUsage.html */
677    } else if (*center == ECMWF) {
678       if (sectLen < 45) {
679          printf ("Warning! Problems with ECMWF PDS extension\n");
680          return 0;
681       }
682       /*
683       sInt4 i_temp;
684       pds += 12;
685       i_temp = GRIB_SIGN_INT2 (pds[3], pds[4]);
686       printf ("ID %d Class %d Type %d Stream %d", pds[0], pds[1], pds[2],
687               i_temp);
688       pds += 5;
689       printf (" Ver %c%c%c%c, ", pds[0], pds[1], pds[2], pds[3]);
690       pds += 4;
691       printf ("Octet-50 %d, Octet-51 %d SectLen %d\n", pds[0], pds[1],
692               sectLen);
693       */
694    } else {
695       printf ("Un-handled possible ensemble section center %u "
696               "subcenter %u\n", *center, *subcenter);
697    }
698    return 0;
699 }
700 
701 /*****************************************************************************
702  * Grib1_Inventory() --
703  *
704  * Arthur Taylor / MDL
705  *
706  * PURPOSE
707  *   Parses the GRIB1 "Product Definition Section" for enough information to
708  * fill out the inventory data structure so we can do a simple inventory on
709  * the file in a similar way to how we did it for GRIB2.
710  *
711  * ARGUMENTS
712  *      fp = An opened GRIB2 file already at the correct message. (Input)
713  * gribLen = The total length of the GRIB1 message. (Input)
714  *     inv = The inventory data structure that we need to fill. (Output)
715  *
716  * FILES/DATABASES: None
717  *
718  * RETURNS: int (could use errSprintf())
719  *  0 = OK
720  * -1 = gribLen is too small.
721  *
722  * HISTORY
723  *   4/2003 Arthur Taylor (MDL/RSIS): Created.
724  *
725  * NOTES
726  *****************************************************************************
727  */
GRIB1_Inventory(VSILFILE * fp,uInt4 gribLen,inventoryType * inv)728 int GRIB1_Inventory (VSILFILE *fp, uInt4 gribLen, inventoryType *inv)
729 {
730    uChar temp[3];        /* Used to determine the section length. */
731    uInt4 sectLen;       /* Length in bytes of the current section. */
732    uChar *pds;          /* The part of the message dealing with the PDS. */
733    pdsG1Type pdsMeta;   /* The pds parsed into a usable data structure. */
734    char f_gds;          /* flag if there is a gds section. */
735    char f_bms;          /* flag if there is a bms section. */
736    short int DSF;       /* Decimal Scale Factor for unpacking the data. */
737    uChar gridID;        /* Which GDS specs to use. */
738    const char *varName; /* The name of the data stored in the grid. */
739    const char *varComment; /* Extra comments about the data stored in grid. */
740    const char *varUnit; /* Holds the name of the unit [K] [%] .. etc */
741    int convert;         /* Conversion method for this variable's unit. */
742    uInt4 curLoc;        /* Where we are in the current GRIB message. */
743    unsigned short int center; /* The Center that created the data */
744    unsigned short int subcenter; /* The Sub Center that created the data */
745 
746    curLoc = 8;
747    if (VSIFReadL(temp, sizeof (char), 3, fp) != 3) {
748       errSprintf ("Ran out of file.\n");
749       return -1;
750    }
751    sectLen = GRIB_UNSIGN_INT3 (*temp, temp[1], temp[2]);
752    if (curLoc + sectLen > gribLen) {
753       errSprintf ("Ran out of data in PDS (GRIB1_Inventory)\n");
754       return -1;
755    }
756    if( sectLen < 3 )
757    {
758        errSprintf ("Invalid sectLen.\n");
759        return -1;
760    }
761    pds = (uChar *) malloc (sectLen * sizeof (uChar));
762    if( pds == nullptr )
763    {
764        errSprintf ("Ran out of memory.\n");
765        return -1;
766    }
767    *pds = *temp;
768    pds[1] = temp[1];
769    pds[2] = temp[2];
770    if (VSIFReadL(pds + 3, sizeof (char), sectLen - 3, fp) + 3 != sectLen) {
771       errSprintf ("Ran out of file.\n");
772       free (pds);
773       return -1;
774    }
775 
776    if (ReadGrib1Sect1 (pds, sectLen, gribLen, &curLoc, &pdsMeta, &f_gds, &gridID,
777                        &f_bms, &DSF, &center, &subcenter) != 0) {
778       preErrSprintf ("Inside GRIB1_Inventory\n");
779       free (pds);
780       return -1;
781    }
782    free (pds);
783    inv->refTime = pdsMeta.refTime;
784    inv->validTime = pdsMeta.validTime;
785    inv->foreSec = inv->validTime - inv->refTime;
786    GRIB1_Table2LookUp (&(pdsMeta), &varName, &varComment, &varUnit,
787                        &convert, center, subcenter);
788    inv->element = (char *) malloc ((1 + strlen (varName)) * sizeof (char));
789    strcpy (inv->element, varName);
790    inv->unitName = (char *) malloc ((1 + 2 + strlen (varUnit)) *
791                                     sizeof (char));
792    snprintf (inv->unitName, (1 + 2 + strlen (varUnit)) *
793                                     sizeof (char), "[%s]", varUnit);
794    inv->comment = (char *) malloc ((1 + strlen (varComment) +
795                                     strlen (varUnit) + 2 + 1) *
796                                    sizeof (char));
797    snprintf (inv->comment, (1 + strlen (varComment) +
798                                     strlen (varUnit) + 2 + 1) *
799                                    sizeof (char),
800              "%s [%s]", varComment, varUnit);
801 
802    GRIB1_Table3LookUp (&(pdsMeta), &(inv->shortFstLevel),
803                        &(inv->longFstLevel));
804 
805    /* Get to the end of the GRIB1 message. */
806    /* (inventory.c : GRIB2Inventory), is responsible for this. */
807    /* fseek (fp, gribLen - sectLen, SEEK_CUR); */
808    return 0;
809 }
810 
GRIB1_RefTime(VSILFILE * fp,uInt4 gribLen,double * refTime)811 int GRIB1_RefTime (VSILFILE *fp, uInt4 gribLen, double *refTime)
812 {
813    uChar temp[3];        /* Used to determine the section length. */
814    uInt4 sectLen;       /* Length in bytes of the current section. */
815    uChar *pds;          /* The part of the message dealing with the PDS. */
816    pdsG1Type pdsMeta;   /* The pds parsed into a usable data structure. */
817    char f_gds;          /* flag if there is a gds section. */
818    char f_bms;          /* flag if there is a bms section. */
819    short int DSF;       /* Decimal Scale Factor for unpacking the data. */
820    uChar gridID;        /* Which GDS specs to use. */
821    uInt4 curLoc;        /* Where we are in the current GRIB message. */
822    unsigned short int center; /* The Center that created the data */
823    unsigned short int subcenter; /* The Sub Center that created the data */
824 
825    curLoc = 8;
826    if (VSIFReadL (temp, sizeof (char), 3, fp) != 3) {
827       errSprintf ("Ran out of file.\n");
828       return -1;
829    }
830    sectLen = GRIB_UNSIGN_INT3 (*temp, temp[1], temp[2]);
831    if (curLoc + sectLen > gribLen) {
832       errSprintf ("Ran out of data in PDS (GRIB1_Inventory)\n");
833       return -1;
834    }
835    pds = (uChar *) malloc (sectLen * sizeof (uChar));
836    *pds = *temp;
837    pds[1] = temp[1];
838    pds[2] = temp[2];
839    if (VSIFReadL (pds + 3, sizeof (char), sectLen - 3, fp) + 3 != sectLen) {
840       errSprintf ("Ran out of file.\n");
841       free (pds);
842       return -1;
843    }
844 
845    if (ReadGrib1Sect1 (pds, sectLen, gribLen, &curLoc, &pdsMeta, &f_gds, &gridID,
846                        &f_bms, &DSF, &center, &subcenter) != 0) {
847       preErrSprintf ("Inside GRIB1_Inventory\n");
848       free (pds);
849       return -1;
850    }
851    free (pds);
852 
853    *refTime = pdsMeta.refTime;
854 
855    /* Get to the end of the GRIB1 message. */
856    /* (inventory.c : GRIB2Inventory), is responsible for this. */
857    /* fseek (fp, gribLen - sectLen, SEEK_CUR); */
858    return 0;
859 }
860 
861 /*****************************************************************************
862  * ReadGrib1Sect2() --
863  *
864  * Arthur Taylor / MDL
865  *
866  * PURPOSE
867  *   Parses the GRIB1 "Grid Definition Section" or section 2, filling out
868  * the gdsMeta data structure.
869  *
870  * ARGUMENTS
871  *     gds = The compressed part of the message dealing with "GDS". (Input)
872  * gribLen = The total length of the GRIB1 message. (Input)
873  *  curLoc = Current location in the GRIB1 message. (Output)
874  * gdsMeta = The filled out gdsMeta data structure. (Output)
875  *
876  * FILES/DATABASES: None
877  *
878  * RETURNS: int (could use errSprintf())
879  *  0 = OK
880  * -1 = gribLen is too small.
881  * -2 = unexpected values in gds.
882  *
883  * HISTORY
884  *   4/2003 Arthur Taylor (MDL/RSIS): Created.
885  *  12/2003 AAT: adas data encoder seems to have # of vertical data = 1, but
886  *        parameters of vertical data = 255, which doesn't make sense.
887  *        Changed the error from "fatal" to a warning in debug mode.
888  *   6/2004 AAT: Modified to allow "extended" lat/lon grids (i.e. stretched or
889  *        stretched and rotated).
890  *
891  * NOTES
892  *****************************************************************************
893  */
ReadGrib1Sect2(uChar * gds,uInt4 gribLen,uInt4 * curLoc,gdsType * gdsMeta)894 static int ReadGrib1Sect2 (uChar *gds, uInt4 gribLen, uInt4 *curLoc,
895                            gdsType *gdsMeta)
896 {
897    uInt4 sectLen;       /* Length in bytes of the current section. */
898    int gridType;        /* Which type of grid. (see enumerated types). */
899    double unit = 1e-3; /* Used for converting to the correct unit. */
900    uInt4 uli_temp;      /* Used for reading a GRIB1 float. */
901    int i;
902    int f_allZero;       /* Used to find out if the "lat/lon" extension part
903                          * is all 0 hence missing. */
904    int f_allOne;        /* Used to find out if the "lat/lon" extension part
905                          * is all 1 hence missing. */
906 
907    if( gribLen < *curLoc || gribLen - *curLoc < 6 ) {
908       errSprintf ("Ran out of data in GDS (GRIB 1 Section 2)\n");
909       return -1;
910    }
911    sectLen = GRIB_UNSIGN_INT3 (*gds, gds[1], gds[2]);
912 #ifdef DEBUG
913 /*
914    printf ("Section 2 length = %ld\n", sectLen);
915 */
916 #endif
917    *curLoc += sectLen;
918    if (*curLoc > gribLen) {
919       errSprintf ("Ran out of data in GDS (GRIB 1 Section 2)\n");
920       return -1;
921    }
922    gds += 3;
923 /*
924 #ifdef DEBUG
925    if ((*gds != 0) || (gds[1] != 255)) {
926       printf ("GRIB1 GDS: Expect (NV = 0) != %d, (PV = 255) != %d\n",
927               *gds, gds[1]);
928       errSprintf ("SectLen == %ld\n", sectLen);
929       errSprintf ("GridType == %d\n", gds[2]);
930    }
931 #endif
932 */
933 #ifdef DEBUG
934    /*if (gds[1] != 255) {
935       printf ("\n\tCaution: GRIB1 GDS: FOR ALL NWS products, PV should be "
936               "255 rather than %u\n", gds[1]);
937    }*/
938 #endif
939    if ((gds[1] != 255) && (gds[1] > 6)) {
940       //errSprintf ("GRIB1 GDS: Expect PV = 255 != %d\n", gds[1]);
941       //return -2;
942    }
943    gds += 2;
944    gridType = *(gds++);
945    switch (gridType) {
946       case GB1S2_LATLON: // Latitude/Longitude Grid
947       case GB1S2_GAUSSIAN_LATLON: // Gaussian Latitude/Longitude
948       case GB1S2_ROTATED: // Rotated Latitude/Longitude
949          if( gridType == GB1S2_ROTATED && (sectLen < 42)) {
950             errSprintf ("For Rotated LatLon GDS, should have at least 42 bytes "
951                         "of data\n");
952             return -1;
953          }
954          if ((sectLen < 32)) {
955             errSprintf ("For LatLon GDS, should have at least 32 bytes "
956                         "of data\n");
957             return -1;
958          }
959          switch(gridType) {
960          case GB1S2_GAUSSIAN_LATLON:
961             gdsMeta->projType = GS3_GAUSSIAN_LATLON;
962             break;
963          case GB1S2_ROTATED:
964             gdsMeta->projType = GS3_ROTATED_LATLON;
965             break;
966          default:
967             gdsMeta->projType = GS3_LATLON;
968             break;
969          }
970          gdsMeta->orientLon = 0;
971          gdsMeta->meshLat = 0;
972          gdsMeta->scaleLat1 = 0;
973          gdsMeta->scaleLat2 = 0;
974          gdsMeta->southLat = 0;
975          gdsMeta->southLon = 0;
976          gdsMeta->center = 0;
977 
978          gdsMeta->Nx = GRIB_UNSIGN_INT2 (*gds, gds[1]);
979          if( gdsMeta->Nx == 65535 )
980          {
981              /* https://rda.ucar.edu/docs/formats/grib/gribdoc/llgrid.html */
982              errSprintf ("Quasi rectangular grid with varying number of grids points per row are not supported\n");
983              return -1;
984          }
985          gds += 2;
986          gdsMeta->Ny = GRIB_UNSIGN_INT2 (*gds, gds[1]);
987          gds += 2;
988          gdsMeta->lat1 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
989          gds += 3;
990          gdsMeta->lon1 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
991          gds += 3;
992 
993          gdsMeta->resFlag = *(gds++);
994          if (gdsMeta->resFlag & 0x40) {
995             gdsMeta->f_sphere = 0;
996             gdsMeta->majEarth = 6378.160;
997             gdsMeta->minEarth = 6356.775;
998          } else {
999             gdsMeta->f_sphere = 1;
1000             gdsMeta->majEarth = 6367.47;
1001             gdsMeta->minEarth = 6367.47;
1002          }
1003 
1004          gdsMeta->lat2 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1005          gds += 3;
1006          gdsMeta->lon2 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1007          gds += 3;
1008          gdsMeta->Dx = GRIB_UNSIGN_INT2 (*gds, gds[1]) * unit;
1009          gds += 2;
1010          if (gridType == GB1S2_GAUSSIAN_LATLON) {
1011             int np = GRIB_UNSIGN_INT2 (*gds, gds[1]); /* parallels between a pole and the equator */
1012             if( np == 0 )
1013             {
1014                 errSprintf ("Invalid Gaussian LatLon\n" );
1015                 return -1;
1016             }
1017             gdsMeta->Dy = 90.0 / np;
1018          } else
1019             gdsMeta->Dy = GRIB_UNSIGN_INT2 (*gds, gds[1]) * unit;
1020          gds += 2;
1021          gdsMeta->scan = *gds;
1022          gdsMeta->f_typeLatLon = 0;
1023 #ifdef DEBUG
1024 /*
1025          printf ("sectLen %ld\n", sectLen);
1026 */
1027 #endif
1028          if (gridType == GB1S2_ROTATED && sectLen >= 42) {
1029             /* Check if all 0's or all 1's, which means f_typeLatLon == 0 */
1030             f_allZero = 1;
1031             f_allOne = 1;
1032             for (i = 0; i < 10; i++) {
1033                if (gds[i] != 0)
1034                   f_allZero = 0;
1035                if (gds[i] != 255)
1036                   f_allOne = 0;
1037             }
1038             if (!f_allZero && !f_allOne) {
1039                gdsMeta->f_typeLatLon = 3;
1040                gds += 5;
1041                gdsMeta->southLat = (GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) *
1042                                    unit);
1043                gds += 3;
1044                gdsMeta->southLon = (GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) *
1045                                    unit);
1046                gds += 3;
1047                MEMCPY_BIG (&uli_temp, gds, sizeof (sInt4));
1048                gdsMeta->angleRotate = fval_360 (uli_temp);
1049             }
1050          }
1051 #if 0
1052          else if (gridType == GB1S2_STRETCHED && sectLen >= 42) {
1053             gds += 5;
1054             /* Check if all 0's or all 1's, which means f_typeLatLon == 0 */
1055             f_allZero = 1;
1056             f_allOne = 1;
1057             for (i = 0; i < 20; i++) {
1058                if (gds[i] != 0)
1059                   f_allZero = 0;
1060                if (gds[i] != 255)
1061                   f_allOne = 0;
1062             }
1063             if (!f_allZero && !f_allOne) {
1064                gdsMeta->f_typeLatLon = 1;
1065                gdsMeta->poleLat = (GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) *
1066                                    unit);
1067                gds += 3;
1068                gdsMeta->poleLon = (GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) *
1069                                    unit);
1070                gds += 3;
1071                MEMCPY_BIG (&uli_temp, gds, sizeof (sInt4));
1072                gdsMeta->stretchFactor = fval_360 (uli_temp);
1073             }
1074          else if (gridType == GB1S2_ROTATED_STRETCHED && sectLen >= 52) {
1075             gds += 5;
1076             /* Check if all 0's or all 1's, which means f_typeLatLon == 0 */
1077             f_allZero = 1;
1078             f_allOne = 1;
1079             for (i = 0; i < 20; i++) {
1080                if (gds[i] != 0)
1081                   f_allZero = 0;
1082                if (gds[i] != 255)
1083                   f_allOne = 0;
1084             }
1085             if (!f_allZero && !f_allOne) {
1086                gdsMeta->f_typeLatLon = 2;
1087                gdsMeta->southLat = (GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) *
1088                                     unit);
1089                gds += 3;
1090                gdsMeta->southLon = (GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) *
1091                                     unit);
1092                gds += 3;
1093                MEMCPY_BIG (&uli_temp, gds, sizeof (sInt4));
1094                gdsMeta->angleRotate = fval_360 (uli_temp);
1095                gds += 4;
1096                gdsMeta->poleLat = (GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) *
1097                                    unit);
1098                gds += 3;
1099                gdsMeta->poleLon = (GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) *
1100                                    unit);
1101                gds += 3;
1102                MEMCPY_BIG (&uli_temp, gds, sizeof (sInt4));
1103                gdsMeta->stretchFactor = fval_360 (uli_temp);
1104             }
1105 #endif
1106 
1107          break;
1108 
1109       case GB1S2_POLAR:
1110          if (sectLen < 32) {
1111             errSprintf ("For Polar GDS, should have 32 bytes of data\n");
1112             return -1;
1113          }
1114          gdsMeta->projType = GS3_POLAR;
1115          gdsMeta->lat2 = 0;
1116          gdsMeta->lon2 = 0;
1117          gdsMeta->southLat = 0;
1118          gdsMeta->southLon = 0;
1119 
1120          gdsMeta->Nx = GRIB_UNSIGN_INT2 (*gds, gds[1]);
1121          gds += 2;
1122          gdsMeta->Ny = GRIB_UNSIGN_INT2 (*gds, gds[1]);
1123          gds += 2;
1124          gdsMeta->lat1 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1125          gds += 3;
1126          gdsMeta->lon1 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1127          gds += 3;
1128 
1129          gdsMeta->resFlag = *(gds++);
1130          if (gdsMeta->resFlag & 0x40) {
1131             gdsMeta->f_sphere = 0;
1132             gdsMeta->majEarth = 6378.160;
1133             gdsMeta->minEarth = 6356.775;
1134          } else {
1135             gdsMeta->f_sphere = 1;
1136             gdsMeta->majEarth = 6367.47;
1137             gdsMeta->minEarth = 6367.47;
1138          }
1139 
1140          gdsMeta->orientLon = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1141          gds += 3;
1142          gdsMeta->Dx = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]);
1143          gds += 3;
1144          gdsMeta->Dy = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]);
1145          gds += 3;
1146          gdsMeta->meshLat = 60; /* Depends on hemisphere. */
1147          gdsMeta->center = *(gds++);
1148          if (gdsMeta->center & GRIB2BIT_1) {
1149             /* South polar stereographic. */
1150             gdsMeta->scaleLat1 = gdsMeta->scaleLat2 = -90;
1151          } else {
1152             /* North polar stereographic. */
1153             gdsMeta->scaleLat1 = gdsMeta->scaleLat2 = 90;
1154          }
1155          gdsMeta->scan = *gds;
1156          break;
1157 
1158       case GB1S2_LAMBERT:
1159          if (sectLen < 42) {
1160             errSprintf ("For Lambert GDS, should have 42 bytes of data\n");
1161             return -1;
1162          }
1163          gdsMeta->projType = GS3_LAMBERT;
1164          gdsMeta->lat2 = 0;
1165          gdsMeta->lon2 = 0;
1166 
1167          gdsMeta->Nx = GRIB_UNSIGN_INT2 (*gds, gds[1]);
1168          gds += 2;
1169          gdsMeta->Ny = GRIB_UNSIGN_INT2 (*gds, gds[1]);
1170          gds += 2;
1171          gdsMeta->lat1 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1172          gds += 3;
1173          gdsMeta->lon1 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1174          gds += 3;
1175 
1176          gdsMeta->resFlag = *(gds++);
1177          if (gdsMeta->resFlag & 0x40) {
1178             gdsMeta->f_sphere = 0;
1179             gdsMeta->majEarth = 6378.160;
1180             gdsMeta->minEarth = 6356.775;
1181          } else {
1182             gdsMeta->f_sphere = 1;
1183             gdsMeta->majEarth = 6367.47;
1184             gdsMeta->minEarth = 6367.47;
1185          }
1186 
1187          gdsMeta->orientLon = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1188          gds += 3;
1189          gdsMeta->Dx = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]);
1190          gds += 3;
1191          gdsMeta->Dy = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]);
1192          gds += 3;
1193          gdsMeta->center = *(gds++);
1194          gdsMeta->scan = *(gds++);
1195          gdsMeta->scaleLat1 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1196          gds += 3;
1197          gdsMeta->scaleLat2 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1198          gds += 3;
1199          gdsMeta->meshLat = gdsMeta->scaleLat1;
1200          gdsMeta->southLat = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1201          gds += 3;
1202          gdsMeta->southLon = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1203          break;
1204 
1205       case GB1S2_MERCATOR:
1206          if (sectLen < 42) {
1207             errSprintf ("For Mercator GDS, should have 42 bytes of data\n");
1208             return -1;
1209          }
1210          gdsMeta->projType = GS3_MERCATOR;
1211          gdsMeta->southLat = 0;
1212          gdsMeta->southLon = 0;
1213          gdsMeta->orientLon = 0;
1214          gdsMeta->center = 0;
1215 
1216          gdsMeta->Nx = GRIB_UNSIGN_INT2 (*gds, gds[1]);
1217          gds += 2;
1218          gdsMeta->Ny = GRIB_UNSIGN_INT2 (*gds, gds[1]);
1219          gds += 2;
1220          gdsMeta->lat1 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1221          gds += 3;
1222          gdsMeta->lon1 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1223          gds += 3;
1224 
1225          gdsMeta->resFlag = *(gds++);
1226          if (gdsMeta->resFlag & 0x40) {
1227             gdsMeta->f_sphere = 0;
1228             gdsMeta->majEarth = 6378.160;
1229             gdsMeta->minEarth = 6356.775;
1230          } else {
1231             gdsMeta->f_sphere = 1;
1232             gdsMeta->majEarth = 6367.47;
1233             gdsMeta->minEarth = 6367.47;
1234          }
1235 
1236          gdsMeta->lat2 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1237          gds += 3;
1238          gdsMeta->lon2 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1239          gds += 3;
1240          gdsMeta->scaleLat1 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) * unit;
1241          gds += 3;
1242          gdsMeta->scaleLat2 = gdsMeta->scaleLat1;
1243          gdsMeta->meshLat = gdsMeta->scaleLat1;
1244          /* Reserved set to 0. */
1245          gds++;
1246          gdsMeta->scan = *(gds++);
1247          gdsMeta->Dx = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]);
1248          gds += 3;
1249          gdsMeta->Dy = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]);
1250          break;
1251 
1252       default:
1253          errSprintf ("Grid projection number is %d\n", gridType);
1254          errSprintf ("Don't know how to handle this grid projection.\n");
1255          return -2;
1256    }
1257    gdsMeta->numPts = gdsMeta->Nx * gdsMeta->Ny;
1258 #ifdef DEBUG
1259 /*
1260 printf ("NumPts = %ld\n", gdsMeta->numPts);
1261 printf ("Nx = %ld, Ny = %ld\n", gdsMeta->Nx, gdsMeta->Ny);
1262 */
1263 #endif
1264    return 0;
1265 }
1266 
1267 /*****************************************************************************
1268  * ReadGrib1Sect3() --
1269  *
1270  * Arthur Taylor / MDL
1271  *
1272  * PURPOSE
1273  *   Parses the GRIB1 "Bit Map Section" or section 3, filling out the bitmap
1274  * as needed.
1275  *
1276  * ARGUMENTS
1277  *     bms = The compressed part of the message dealing with "BMS". (Input)
1278  * gribLen = The total length of the GRIB1 message. (Input)
1279  *  curLoc = Current location in the GRIB1 message. (Output)
1280  * pBitmap = Pointer to the extracted bitmap. (Output)
1281  *    NxNy = The total size of the grid. (Input)
1282  *
1283  * FILES/DATABASES: None
1284  *
1285  * RETURNS: int (could use errSprintf())
1286  *  0 = OK
1287  * -1 = gribLen is too small.
1288  * -2 = unexpected values in bms.
1289  *
1290  * HISTORY
1291  *   4/2003 Arthur Taylor (MDL/RSIS): Created.
1292  *
1293  * NOTES
1294  *****************************************************************************
1295  */
1296 static int ReadGrib1Sect3 (uChar *bms, uInt4 gribLen, uInt4 *curLoc,
1297                            uChar **pBitmap, uInt4 NxNy)
1298 {
1299    uInt4 sectLen;       /* Length in bytes of the current section. */
1300    short int numeric;   /* Determine if this is a predefined bitmap */
1301    uChar bits;          /* Used to locate which bit we are currently using. */
1302    uInt4 i;             /* Helps traverse the bitmap. */
1303 
1304    *pBitmap = nullptr;
1305 
1306    uInt4 bmsRemainingSize = gribLen - *curLoc;
1307    if( bmsRemainingSize < 6 )
1308    {
1309       errSprintf ("Ran out of data in BMS (GRIB 1 Section 3)\n");
1310       return -1;
1311    }
1312    sectLen = GRIB_UNSIGN_INT3 (*bms, bms[1], bms[2]);
1313 #ifdef DEBUG
1314 /*
1315    printf ("Section 3 length = %ld\n", sectLen);
1316 */
1317 #endif
1318    *curLoc += sectLen;
1319    if (*curLoc > gribLen) {
1320       errSprintf ("Ran out of data in BMS (GRIB 1 Section 3)\n");
1321       return -1;
1322    }
1323    bms += 3;
1324    /* Assert: *bms currently points to number of unused bits at end of BMS. */
1325    if (NxNy + *bms + 6 * 8 != sectLen * 8) {
1326       errSprintf ("NxNy + # of unused bits != # of available bits\n");
1327       // commented out to avoid unsigned integer overflow
1328       // (sInt4) (NxNy + *bms), (sInt4) ((sectLen - 6) * 8));
1329       return -2;
1330    }
1331    bms++;
1332    /* Assert: Non-zero "numeric" means predefined bitmap. */
1333    numeric = GRIB_UNSIGN_INT2 (*bms, bms[1]);
1334    bms += 2;
1335    if (numeric != 0) {
1336       errSprintf ("Don't handle predefined bitmaps yet.\n");
1337       return -2;
1338    }
1339    bmsRemainingSize -= 6;
1340    if( bmsRemainingSize < (NxNy+7) / 8 )
1341    {
1342       errSprintf ("Ran out of data in BMS (GRIB 1 Section 3)\n");
1343       return -1;
1344    }
1345    *pBitmap = (uChar*) malloc(NxNy);
1346    auto bitmap = *pBitmap;
1347    if( bitmap== nullptr )
1348    {
1349       errSprintf ("Ran out of memory in allocating bitmap (GRIB 1 Section 3)\n");
1350       return -1;
1351    }
1352    bits = 0x80;
1353    for (i = 0; i < NxNy; i++) {
1354       *(bitmap++) = (*bms) & bits;
1355       bits = bits >> 1;
1356       if (bits == 0) {
1357          bms++;
1358          bits = 0x80;
1359       }
1360    }
1361    return 0;
1362 }
1363 
1364 #ifdef USE_UNPACKCMPLX
1365 static int UnpackCmplx (uChar *bds, CPL_UNUSED uInt4 gribLen, CPL_UNUSED uInt4 *curLoc,
1366                         CPL_UNUSED short int DSF, CPL_UNUSED double *data, CPL_UNUSED grib_MetaData *meta,
1367                         CPL_UNUSED char f_bms, CPL_UNUSED uChar *bitmap, CPL_UNUSED double unitM,
1368                         CPL_UNUSED double unitB, CPL_UNUSED short int ESF, CPL_UNUSED double refVal,
1369                         uChar numBits, uChar f_octet14)
1370 {
1371    uInt4 secLen;
1372    int N1;
1373    int N2;
1374    int P1;
1375    int P2;
1376    uChar octet14;
1377    uChar f_maxtrixValues;
1378    uChar f_secBitmap = 0;
1379    uChar f_secValDiffWid;
1380    int i;
1381    uInt4 uli_temp;      /* Used to store sInt4s (temporarily) */
1382    uChar bufLoc;        /* Keeps track of where to start getting more data
1383                          * out of the packed data stream. */
1384    size_t numUsed;      /* How many bytes were used in a given call to
1385                          * memBitRead. */
1386    uChar *width;
1387 
1388    secLen = 11;
1389    N1 = GRIB_UNSIGN_INT2 (bds[0], bds[1]);
1390    octet14 = bds[2];
1391    printf ("octet14, %d\n", octet14);
1392    if (f_octet14) {
1393       f_maxtrixValues = octet14 & GRIB2BIT_2;
1394       f_secBitmap = octet14 & GRIB2BIT_3;
1395       f_secValDiffWid = octet14 & GRIB2BIT_4;
1396       printf ("f_matrixValues, f_secBitmap, f_secValeDiffWid %d %d %d\n",
1397               f_maxtrixValues, f_secBitmap, f_secValDiffWid);
1398    }
1399    N2 = GRIB_UNSIGN_INT2 (bds[3], bds[4]);
1400    P1 = GRIB_UNSIGN_INT2 (bds[5], bds[6]);
1401    P2 = GRIB_UNSIGN_INT2 (bds[7], bds[8]);
1402    printf ("N1 N2 P1 P2 : %d %d %d %d\n", N1, N2, P1, P2);
1403    printf ("Reserved %u\n", bds[9]);
1404    bds += 10;
1405    secLen += 10;
1406 
1407    width = (uChar *) malloc (P1 * sizeof (uChar));
1408 
1409    for (i = 0; i < P1; i++) {
1410       width[i] = *bds;
1411       printf ("(Width %d %u)\n", i, width[i]);
1412       bds++;
1413       secLen++;
1414    }
1415    if (f_secBitmap) {
1416       bufLoc = 8;
1417       for (i = 0; i < P2; i++) {
1418          memBitRead (&uli_temp, sizeof (sInt4), bds, 1, &bufLoc, &numUsed);
1419          printf ("(%d %u) ", i, uli_temp);
1420          if (numUsed != 0) {
1421             printf ("\n");
1422             bds += numUsed;
1423             secLen++;
1424          }
1425       }
1426       if (bufLoc != 8) {
1427          bds++;
1428          secLen++;
1429       }
1430       printf ("Observed Sec Len %u\n", secLen);
1431    } else {
1432       /* Jump over widths and secondary bitmap */
1433       bds += (N1 - 21);
1434       secLen += (N1 - 21);
1435    }
1436 
1437    bufLoc = 8;
1438    for (i = 0; i < P1; i++) {
1439       memBitRead (&uli_temp, sizeof (sInt4), bds, numBits, &bufLoc, &numUsed);
1440       printf ("(%d %u) (numUsed %ld numBits %d)", i, uli_temp,
1441               (long) numUsed, numBits);
1442       if (numUsed != 0) {
1443          printf ("\n");
1444          bds += numUsed;
1445          secLen++;
1446       }
1447    }
1448    if (bufLoc != 8) {
1449       // cppcheck-suppress uselessAssignmentPtrArg
1450       bds++;
1451       secLen++;
1452    }
1453 
1454    printf ("Observed Sec Len %u\n", secLen);
1455    printf ("N2 = %d\n", N2);
1456 
1457    errSprintf ("Don't know how to handle Complex GRIB1 packing yet.\n");
1458    free (width);
1459    return -2;
1460 
1461 }
1462 #endif /* USE_UNPACKCMPLX */
1463 
1464 /*****************************************************************************
1465  * ReadGrib1Sect4() --
1466  *
1467  * Arthur Taylor / MDL
1468  *
1469  * PURPOSE
1470  *   Unpacks the "Binary Data Section" or section 4.
1471  *
1472  * ARGUMENTS
1473  *     bds = The compressed part of the message dealing with "BDS". (Input)
1474  * gribLen = The total length of the GRIB1 message. (Input)
1475  *  curLoc = Current location in the GRIB1 message. (Input/Output)
1476  *     DSF = Decimal Scale Factor for unpacking the data. (Input)
1477  *    data = The extracted grid. (Output)
1478  *    meta = The meta data associated with the grid (Input/Output)
1479  *   f_bms = True if bitmap is to be used. (Input)
1480  *  bitmap = 0 if missing data, 1 if valid data. (Input)
1481  *   unitM = The M unit conversion value in equation y = Mx + B. (Input)
1482  *   unitB = The B unit conversion value in equation y = Mx + B. (Input)
1483  *
1484  * FILES/DATABASES: None
1485  *
1486  * RETURNS: int (could use errSprintf())
1487  *  0 = OK
1488  * -1 = gribLen is too small.
1489  * -2 = unexpected values in bds.
1490  *
1491  * HISTORY
1492  *   4/2003 Arthur Taylor (MDL/RSIS): Created
1493  *   3/2004 AAT: Switched {# Pts * (# Bits in a Group) +
1494  *          # of unused bits != # of available bits} to a warning from an
1495  *          error.
1496  *
1497  * NOTES
1498  * 1) See metaparse.c : ParseGrid()
1499  * 2) Currently, only handles "Simple pack".
1500  *****************************************************************************
1501  */
1502 static int ReadGrib1Sect4 (uChar *bds, uInt4 gribLen, uInt4 *curLoc,
1503                            short int DSF, double *data, grib_MetaData *meta,
1504                            char f_bms, uChar *bitmap, double unitM,
1505                            double unitB)
1506 {
1507    uInt4 sectLen;       /* Length in bytes of the current section. */
1508    short int ESF;       /* Power of 2 scaling factor. */
1509    uInt4 uli_temp;      /* Used to store sInt4s (temporarily) */
1510    double refVal;       /* The reference value for the grid, also the minimum
1511                          * value. */
1512    uChar numBits;       /* # of bits for a single element of data. */
1513    uChar numUnusedBit;  /* # of extra bits at end of record. */
1514    uChar f_spherHarm;   /* Flag if data contains Spherical Harmonics. */
1515    uChar f_cmplxPack;   /* Flag if complex packing was used. */
1516 #ifdef USE_UNPACKCMPLX
1517    uChar f_octet14;     /* Flag if octet 14 was used. */
1518 #endif
1519    uChar bufLoc;        /* Keeps track of where to start getting more data
1520                          * out of the packed data stream. */
1521    uChar f_convert;     /* Determine if scan mode implies that we have to do
1522                          * manipulation as we read the grid to get desired
1523                          * internal scan mode. */
1524    uInt4 i;             /* Used to traverse the grid. */
1525    size_t numUsed;      /* How many bytes were used in a given call to
1526                          * memBitRead. */
1527    double d_temp;       /* Holds the extracted data until we put it in data */
1528    sInt4 newIndex;      /* Where to put the answer (primarily if f_convert) */
1529    sInt4 x;             /* Used to help compute newIndex , if f_convert. */
1530    sInt4 y;             /* Used to help compute newIndex , if f_convert. */
1531    double resetPrim;    /* If possible, used to reset the primary missing
1532                          * value from 9.999e20 to a reasonable # (9999) */
1533 
1534    if (meta->gds.Nx * meta->gds.Ny != meta->gds.numPts) {
1535       errSprintf ("(Nx * Ny != numPts) ?? in BDS (GRIB 1 Section 4)\n");
1536       return -2;
1537    }
1538    if( *curLoc >= gribLen )
1539        return -1;
1540 
1541    uInt4 bdsRemainingSize = gribLen - *curLoc;
1542    if( bdsRemainingSize < 3 )
1543        return -1;
1544 
1545    sectLen = GRIB_UNSIGN_INT3 (*bds, bds[1], bds[2]);
1546 #ifdef DEBUG
1547 /*
1548    printf ("Section 4 length = %ld\n", sectLen);
1549 */
1550 #endif
1551    *curLoc += sectLen;
1552    if (*curLoc > gribLen) {
1553       errSprintf ("Ran out of data in BDS (GRIB 1 Section 4)\n");
1554       return -1;
1555    }
1556    bds += 3;
1557    bdsRemainingSize -= 3;
1558 
1559    /* Assert: bds now points to the main pack flag. */
1560    if( bdsRemainingSize < 1 )
1561        return -1;
1562    f_spherHarm = (*bds) & GRIB2BIT_1;
1563    f_cmplxPack = (*bds) & GRIB2BIT_2;
1564    meta->gridAttrib.fieldType = (*bds) & GRIB2BIT_3;
1565 #ifdef USE_UNPACKCMPLX
1566    f_octet14 = (*bds) & GRIB2BIT_4;
1567 #endif
1568 
1569    numUnusedBit = (*bds) & 0x0f;
1570 #ifdef DEBUG
1571 /*
1572    printf ("bds byte flag = %d\n", *bds);
1573    printf ("Number of unused bits = %d\n", numUnusedBit);
1574 */
1575 #endif
1576    if (f_spherHarm) {
1577       errSprintf ("Don't know how to handle Spherical Harmonics yet.\n");
1578       return -2;
1579    }
1580 /*
1581    if (f_octet14) {
1582       errSprintf ("Don't know how to handle Octet 14 data yet.\n");
1583       errSprintf ("bds byte flag = %d\n", *bds);
1584       errSprintf ("bds byte: %d %d %d %d\n", f_spherHarm, f_cmplxPack,
1585                   meta->gridAttrib.fieldType, f_octet14);
1586       return -2;
1587    }
1588 */
1589    if (f_cmplxPack) {
1590       meta->gridAttrib.packType = 2;
1591    } else {
1592       meta->gridAttrib.packType = 0;
1593    }
1594    bds++;
1595    bdsRemainingSize --;
1596 
1597    /* Assert: bds now points to E (power of 2 scaling factor). */
1598    if( bdsRemainingSize < 2 )
1599        return -1;
1600    ESF = GRIB_SIGN_INT2 (*bds, bds[1]);
1601    bds += 2;
1602    bdsRemainingSize -= 2;
1603 
1604    if( bdsRemainingSize < 4 )
1605        return -1;
1606    MEMCPY_BIG (&uli_temp, bds, sizeof (sInt4));
1607    refVal = fval_360 (uli_temp);
1608    bds += 4;
1609    bdsRemainingSize -= 4;
1610 
1611    /* Assert: bds is now the number of bits in a group. */
1612    if( bdsRemainingSize < 1 )
1613        return -1;
1614    numBits = *bds;
1615 /*
1616 #ifdef DEBUG
1617    printf ("refValue %f numBits %d\n", refVal, numBits);
1618    printf ("ESF %d DSF %d\n", ESF, DSF);
1619 #endif
1620 */
1621    if (f_cmplxPack) {
1622 #ifdef USE_UNPACKCMPLX
1623       bds++;
1624       bdsRemainingSize --;
1625       return UnpackCmplx (bds, gribLen, curLoc, DSF, data, meta, f_bms,
1626                           bitmap, unitM, unitB, ESF, refVal, numBits,
1627                           f_octet14);
1628 #else
1629       errSprintf ("Don't know how to handle Complex GRIB1 packing yet.\n");
1630       return -2;
1631 #endif
1632    }
1633 
1634    if (!f_bms && (
1635        sectLen < 11 ||
1636        (numBits > 0 && meta->gds.numPts > UINT_MAX / numBits) ||
1637        (meta->gds.numPts * numBits > UINT_MAX - numUnusedBit))) {
1638      printf ("numPts * (numBits in a Group) + # of unused bits != "
1639               "# of available bits\n");
1640    }
1641    else if (!f_bms &&
1642             (meta->gds.numPts * numBits + numUnusedBit) != (sectLen - 11) * 8) {
1643       printf ("numPts * (numBits in a Group) + # of unused bits %d != "
1644               "# of available bits %d\n",
1645               (sInt4) (meta->gds.numPts * numBits + numUnusedBit),
1646               (sInt4) ((sectLen - 11) * 8));
1647 /*
1648       errSprintf ("numPts * (numBits in a Group) + # of unused bits %ld != "
1649                   "# of available bits %ld\n",
1650                   (sInt4) (meta->gds.numPts * numBits + numUnusedBit),
1651                   (sInt4) ((sectLen - 11) * 8));
1652       return -2;
1653 */
1654    }
1655    if (numBits > 32) {
1656       errSprintf ("The number of bits per number is larger than 32?\n");
1657       return -2;
1658    }
1659    bds++;
1660    bdsRemainingSize -= 1;
1661 
1662    /* Convert Units. */
1663    {
1664    double pow_10_DSF = pow (10.0, DSF);
1665    if( pow_10_DSF == 0.0 ) {
1666       errSprintf ("pow_10_DSF == 0.0\n");
1667       return -2;
1668    }
1669    if (unitM == -10) {
1670       meta->gridAttrib.min = pow (10.0, (refVal * pow (2.0, ESF) /
1671                                        pow_10_DSF));
1672    } else {
1673 /*      meta->gridAttrib.min = unitM * (refVal / pow (10.0, DSF)) + unitB; */
1674       meta->gridAttrib.min = unitM * (refVal * pow (2.0, ESF) /
1675                                       pow_10_DSF) + unitB;
1676    }
1677    }
1678 
1679    meta->gridAttrib.max = meta->gridAttrib.min;
1680    meta->gridAttrib.f_maxmin = 1;
1681    meta->gridAttrib.numMiss = 0;
1682    if (refVal >= std::numeric_limits<float>::max() || CPLIsNan(refVal)) {
1683       meta->gridAttrib.refVal = std::numeric_limits<float>::max();
1684    } else if (refVal <= -std::numeric_limits<float>::max()) {
1685       meta->gridAttrib.refVal = -std::numeric_limits<float>::max();
1686    } else {
1687       meta->gridAttrib.refVal = static_cast<float>(refVal);
1688    }
1689    meta->gridAttrib.ESF = ESF;
1690    meta->gridAttrib.DSF = DSF;
1691    bufLoc = 8;
1692    /* Internally we use scan = 0100.  Scan is usually 0100 but if need be, we
1693     * can convert it. */
1694    f_convert = ((meta->gds.scan & 0xe0) != 0x40);
1695 
1696    if (f_bms) {
1697       meta->gridAttrib.f_miss = 1;
1698       meta->gridAttrib.missPri = UNDEFINED;
1699    }
1700    else
1701    {
1702       meta->gridAttrib.f_miss = 0;
1703    }
1704 
1705    if (f_bms) {
1706 /*
1707 #ifdef DEBUG
1708       printf ("There is a bitmap?\n");
1709 #endif
1710 */
1711       /* Start unpacking the data, assuming there is a bitmap. */
1712       for (i = 0; i < meta->gds.numPts; i++) {
1713          /* Find the destination index. */
1714          if (f_convert) {
1715             /* ScanIndex2XY returns value as if scan was 0100 */
1716             ScanIndex2XY (i, &x, &y, meta->gds.scan, meta->gds.Nx,
1717                           meta->gds.Ny);
1718             newIndex = (x - 1) + (y - 1) * meta->gds.Nx;
1719          } else {
1720             newIndex = i;
1721          }
1722          /* A 0 in bitmap means no data. A 1 in bitmap means data. */
1723          // cppcheck-suppress nullPointer
1724          if (!bitmap[i]) {
1725             meta->gridAttrib.numMiss++;
1726             if( data ) data[newIndex] = UNDEFINED;
1727          } else {
1728             if (numBits != 0) {
1729                 if( ((int)bdsRemainingSize - 1) * 8 + bufLoc < (int)numBits )
1730                     return -1;
1731                memBitRead (&uli_temp, sizeof (sInt4), bds, numBits,
1732                            &bufLoc, &numUsed);
1733                assert( numUsed <= bdsRemainingSize );
1734                bds += numUsed;
1735                bdsRemainingSize -= (uInt4)numUsed;
1736                d_temp = (refVal + (uli_temp * pow (2.0, ESF))) / pow (10.0, DSF);
1737                /* Convert Units. */
1738                if (unitM == -10) {
1739                   d_temp = pow (10.0, d_temp);
1740                } else {
1741                   d_temp = unitM * d_temp + unitB;
1742                }
1743                if (meta->gridAttrib.max < d_temp) {
1744                   meta->gridAttrib.max = d_temp;
1745                }
1746                if( data ) data[newIndex] = d_temp;
1747             } else {
1748                /* Assert: d_temp = unitM * refVal / pow (10.0,DSF) + unitB. */
1749                /* Assert: min = unitM * refVal / pow (10.0, DSF) + unitB. */
1750                if( data ) data[newIndex] = meta->gridAttrib.min;
1751             }
1752          }
1753       }
1754       /* Reset the missing value to UNDEFINED_PRIM if possible.  If not
1755        * possible, make sure UNDEFINED is outside the range.  If UNDEFINED
1756        * is_ in the range, choose max + 1 for missing. */
1757       resetPrim = 0;
1758       if ((meta->gridAttrib.max < UNDEFINED_PRIM) ||
1759           (meta->gridAttrib.min > UNDEFINED_PRIM)) {
1760          resetPrim = UNDEFINED_PRIM;
1761       } else if ((meta->gridAttrib.max >= UNDEFINED) &&
1762                  (meta->gridAttrib.min <= UNDEFINED)) {
1763          resetPrim = meta->gridAttrib.max + 1;
1764       }
1765       if (resetPrim != 0) {
1766          meta->gridAttrib.missPri = resetPrim;
1767       }
1768       if (data != nullptr && resetPrim != 0) {
1769          for (i = 0; i < meta->gds.numPts; i++) {
1770             /* Find the destination index. */
1771             if (f_convert) {
1772                /* ScanIndex2XY returns value as if scan was 0100 */
1773                ScanIndex2XY (i, &x, &y, meta->gds.scan, meta->gds.Nx,
1774                              meta->gds.Ny);
1775                newIndex = (x - 1) + (y - 1) * meta->gds.Nx;
1776             } else {
1777                newIndex = i;
1778             }
1779             // cppcheck-suppress nullPointer
1780             if (!bitmap[i]) {
1781                data[newIndex] = resetPrim;
1782             }
1783          }
1784       }
1785 
1786    } else {
1787 
1788       if( !data )
1789         return 0;
1790 
1791 #ifdef DEBUG
1792 /*
1793       printf ("There is no bitmap?\n");
1794 */
1795 #endif
1796 
1797       /* Start unpacking the data, assuming there is NO bitmap. */
1798       for (i = 0; i < meta->gds.numPts; i++) {
1799          if (numBits != 0) {
1800             /* Find the destination index. */
1801             if (f_convert) {
1802                /* ScanIndex2XY returns value as if scan was 0100 */
1803                ScanIndex2XY (i, &x, &y, meta->gds.scan, meta->gds.Nx,
1804                              meta->gds.Ny);
1805                newIndex = (x - 1) + (y - 1) * meta->gds.Nx;
1806             } else {
1807                newIndex = i;
1808             }
1809 
1810             if( ((int)bdsRemainingSize - 1) * 8 + bufLoc < (int)numBits )
1811                 return -1;
1812             memBitRead (&uli_temp, sizeof (sInt4), bds, numBits, &bufLoc,
1813                         &numUsed);
1814             assert( numUsed <= bdsRemainingSize );
1815             bds += numUsed;
1816             bdsRemainingSize -= (uInt4)numUsed;
1817             d_temp = (refVal + (uli_temp * pow (2.0, ESF))) / pow (10.0, DSF);
1818 
1819 #ifdef DEBUG
1820 /*
1821             if (i == 1) {
1822                printf ("refVal %f, uli_temp %ld, ans %f\n", refVal, uli_temp,
1823                        d_temp);
1824                printf ("numBits %d, bufLoc %d, numUsed %d\n", numBits,
1825                        bufLoc, numUsed);
1826             }
1827 */
1828 #endif
1829 
1830             /* Convert Units. */
1831             if (unitM == -10) {
1832                d_temp = pow (10.0, d_temp);
1833             } else {
1834                d_temp = unitM * d_temp + unitB;
1835             }
1836             if (meta->gridAttrib.max < d_temp) {
1837                meta->gridAttrib.max = d_temp;
1838             }
1839             data[newIndex] = d_temp;
1840          } else {
1841             /* Assert: whole array = unitM * refVal + unitB. */
1842             /* Assert: *min = unitM * refVal + unitB. */
1843             data[i] = meta->gridAttrib.min;
1844          }
1845       }
1846    }
1847    return 0;
1848 }
1849 
1850 /*****************************************************************************
1851  * ReadGrib1Record() --
1852  *
1853  * Arthur Taylor / MDL
1854  *
1855  * PURPOSE
1856  *   Reads in a GRIB1 message, and parses the data into various data
1857  * structures, for use with other code.
1858  *
1859  * ARGUMENTS
1860  *           fp = An opened GRIB2 file already at the correct message. (Input)
1861  *       f_unit = 0 use GRIB2 units, 1 use English, 2 use metric. (Input)
1862  *    Grib_Data = The read in GRIB2 grid. (Output)
1863  * grib_DataLen = Size of Grib_Data. (Output)
1864  *         meta = A filled in meta structure (Output)
1865  *           IS = The structure containing all the arrays that the
1866  *                unpacker uses (Output)
1867  *        sect0 = Already read in section 0 data. (Input)
1868  *      gribLen = Length of the GRIB1 message. (Input)
1869  *     majEarth = Used to override the GRIB major axis of earth. (Input)
1870  *     minEarth = Used to override the GRIB minor axis of earth. (Input)
1871  *
1872  * FILES/DATABASES:
1873  *   An already opened file pointing to the desired GRIB1 message.
1874  *
1875  * RETURNS: int (could use errSprintf())
1876  *  0 = OK
1877  * -1 = Problems reading in the PDS.
1878  * -2 = Problems reading in the GDS.
1879  * -3 = Problems reading in the BMS.
1880  * -4 = Problems reading in the BDS.
1881  * -5 = Problems reading the closing section.
1882  *
1883  * HISTORY
1884  *   4/2003 Arthur Taylor (MDL/RSIS): Created
1885  *   5/2003 AAT: Was not updating offset.  It should be updated by
1886  *               calling routine anyways, so I got rid of the parameter.
1887  *   7/2003 AAT: Allowed user to override the radius of earth.
1888  *   8/2003 AAT: Found a memory Leak (Had been setting unitName to NULL).
1889  *   2/2004 AAT: Added maj/min earth override.
1890  *   3/2004 AAT: Added ability to change units.
1891  *
1892  * NOTES
1893  * 1) Could also compare GDS with the one specified by gridID
1894  * 2) Could add gridID support.
1895  * 3) Should add unitM / unitB support.
1896  *****************************************************************************
1897  */
1898 int ReadGrib1Record (VSILFILE *fp, sChar f_unit, double **Grib_Data,
1899                      uInt4 *grib_DataLen, grib_MetaData *meta,
1900                      IS_dataType *IS, sInt4 sect0[SECT0LEN_WORD],
1901                      uInt4 gribLen, double majEarth, double minEarth)
1902 {
1903    sInt4 nd5;           /* Size of grib message rounded up to the nearest *
1904                          * sInt4. */
1905    uChar *c_ipack;      /* A char ptr to the message stored in IS->ipack */
1906    uInt4 curLoc;        /* Current location in the GRIB message. */
1907    char f_gds;          /* flag if there is a gds section. */
1908    char f_bms;          /* flag if there is a bms section. */
1909    double *grib_Data = nullptr;   /* A pointer to Grib_Data for ease of manipulation. */
1910    uChar *bitmap = nullptr; /* A char field (0=noData, 1=data) set up in BMS. */
1911    short int DSF;       /* Decimal Scale Factor for unpacking the data. */
1912    double unitM = 1;    /* M in y = Mx + B, for unit conversion. */
1913    double unitB = 0;    /* B in y = Mx + B, for unit conversion. */
1914    uChar gridID;        /* Which GDS specs to use. */
1915    const char *varName; /* The name of the data stored in the grid. */
1916    const char *varComment; /* Extra comments about the data stored in grid. */
1917    const char *varUnit; /* Holds the name of the unit [K] [%] .. etc */
1918    sInt4 li_temp;       /* Used to make sure section 5 is 7777. */
1919    char unitName[15];   /* Holds the string name of the current unit. */
1920    int unitLen;         /* String length of string name of current unit. */
1921 
1922    /* Make room for entire message, and read it in. */
1923    /* nd5 needs to be gribLen in (sInt4) units rounded up. */
1924    nd5 = (gribLen + 3) / 4;
1925    if (nd5 > IS->ipackLen) {
1926       if( gribLen > 100 * 1024 * 1024 )
1927       {
1928          vsi_l_offset curPos = VSIFTellL(fp);
1929          VSIFSeekL(fp, 0, SEEK_END);
1930          vsi_l_offset fileSize = VSIFTellL(fp);
1931          VSIFSeekL(fp, curPos, SEEK_SET);
1932          if( fileSize < gribLen )
1933          {
1934             errSprintf("File too short");
1935             return -1;
1936          }
1937       }
1938       sInt4* newipack = (sInt4 *) realloc ((void *) (IS->ipack),
1939                                      nd5 * sizeof (sInt4));
1940       if( newipack == nullptr )
1941       {
1942           errSprintf ("Out of memory\n");
1943           return -1;
1944       }
1945       IS->ipackLen = nd5;
1946       IS->ipack = newipack;
1947    }
1948    c_ipack = (uChar *) IS->ipack;
1949    /* Init last sInt4 to 0, to make sure that the padded bytes are 0. */
1950    IS->ipack[nd5 - 1] = 0;
1951    /* Init first 2 sInt4 to sect0. */
1952    memcpy (c_ipack, sect0, SECT0LEN_WORD * 2);
1953    /* Read in the rest of the message. */
1954    if (VSIFReadL (c_ipack + SECT0LEN_WORD * 2, sizeof (char),
1955               (gribLen - SECT0LEN_WORD * 2), fp) + SECT0LEN_WORD * 2 != gribLen) {
1956       errSprintf ("Ran out of file\n");
1957       return -1;
1958    }
1959 
1960    /* Preceding was in degrib2, next part is specific to GRIB1. */
1961    curLoc = 8;
1962    if (ReadGrib1Sect1 (c_ipack + curLoc, gribLen - curLoc, gribLen, &curLoc, &(meta->pds1),
1963                        &f_gds, &gridID, &f_bms, &DSF, &(meta->center),
1964                        &(meta->subcenter)) != 0) {
1965       preErrSprintf ("Inside ReadGrib1Record\n");
1966       return -1;
1967    }
1968 
1969    /* Get the Grid Definition Section. */
1970    if (f_gds) {
1971       if (ReadGrib1Sect2 (c_ipack + curLoc, gribLen, &curLoc,
1972                           &(meta->gds)) != 0) {
1973          preErrSprintf ("Inside ReadGrib1Record\n");
1974          return -2;
1975       }
1976       /* Could also compare GDS with the one specified by gridID? */
1977    } else {
1978       errSprintf ("Don't know how to handle a gridID lookup yet.\n");
1979       return -2;
1980    }
1981    meta->pds1.gridID = gridID;
1982    /* Allow data originating from NCEP to be 6371.2 by default. */
1983    if (meta->center == NMC) {
1984       if (meta->gds.majEarth == 6367.47) {
1985          meta->gds.f_sphere = 1;
1986          meta->gds.majEarth = 6371.2;
1987          meta->gds.minEarth = 6371.2;
1988       }
1989    }
1990    if ((majEarth > 6300) && (majEarth < 6400)) {
1991       if ((minEarth > 6300) && (minEarth < 6400)) {
1992          meta->gds.f_sphere = 0;
1993          meta->gds.majEarth = majEarth;
1994          meta->gds.minEarth = minEarth;
1995          if (majEarth == minEarth) {
1996             meta->gds.f_sphere = 1;
1997          }
1998       } else {
1999          meta->gds.f_sphere = 1;
2000          meta->gds.majEarth = majEarth;
2001          meta->gds.minEarth = majEarth;
2002       }
2003    }
2004 
2005    if( Grib_Data )
2006    {
2007      /* Allocate memory for the grid. */
2008      if (meta->gds.numPts > *grib_DataLen) {
2009       if( meta->gds.numPts > 100 * 1024 * 1024 )
2010       {
2011           vsi_l_offset curPos = VSIFTellL(fp);
2012           VSIFSeekL(fp, 0, SEEK_END);
2013           vsi_l_offset fileSize = VSIFTellL(fp);
2014           VSIFSeekL(fp, curPos, SEEK_SET);
2015           // allow a compression ratio of 1:1000
2016           if( meta->gds.numPts / 1000 > (uInt4)fileSize )
2017           {
2018             errSprintf ("ERROR: File too short\n");
2019             *grib_DataLen = 0;
2020             *Grib_Data = nullptr;
2021             return -2;
2022           }
2023       }
2024 
2025       *grib_DataLen = meta->gds.numPts;
2026       *Grib_Data = (double *) realloc ((void *) (*Grib_Data),
2027                                        (*grib_DataLen) * sizeof (double));
2028       if (!(*Grib_Data))
2029       {
2030         *grib_DataLen = 0;
2031         return -1;
2032       }
2033      }
2034      grib_Data = *Grib_Data;
2035    }
2036 
2037    /* Get the Bit Map Section. */
2038    if (f_bms) {
2039       if (ReadGrib1Sect3 (c_ipack + curLoc, gribLen, &curLoc, &bitmap,
2040                           meta->gds.numPts) != 0) {
2041          free (bitmap);
2042          preErrSprintf ("Inside ReadGrib1Record\n");
2043          return -3;
2044       }
2045    }
2046 
2047    /* Figure out some basic stuff about the grid. */
2048    /* Following is similar to metaparse.c : ParseElemName */
2049    GRIB1_Table2LookUp (&(meta->pds1), &varName, &varComment, &varUnit,
2050                        &(meta->convert), meta->center, meta->subcenter);
2051    meta->element = (char *) realloc ((void *) (meta->element),
2052                                      (1 + strlen (varName)) * sizeof (char));
2053    strcpy (meta->element, varName);
2054    meta->unitName = (char *) realloc ((void *) (meta->unitName),
2055                                       (1 + 2 + strlen (varUnit)) *
2056                                       sizeof (char));
2057    snprintf (meta->unitName,
2058             (1 + 2 + strlen (varUnit)) *
2059                                       sizeof (char),
2060             "[%s]", varUnit);
2061    meta->comment = (char *) realloc ((void *) (meta->comment),
2062                                      (1 + strlen (varComment) +
2063                                       strlen (varUnit)
2064                                       + 2 + 1) * sizeof (char));
2065    snprintf (meta->comment,
2066             (1 + strlen (varComment) +
2067                                       strlen (varUnit)
2068                                       + 2 + 1) * sizeof (char),
2069             "%s [%s]", varComment, varUnit);
2070 
2071    if (ComputeUnit (meta->convert, meta->unitName, f_unit, &unitM, &unitB,
2072                     unitName) == 0) {
2073       unitLen = static_cast<int>(strlen (unitName));
2074       meta->unitName = (char *) realloc ((void *) (meta->unitName),
2075                                          1 + unitLen * sizeof (char));
2076       memcpy (meta->unitName, unitName, unitLen);
2077       meta->unitName[unitLen] = '\0';
2078    }
2079 
2080    /* Read the GRID. */
2081    if (ReadGrib1Sect4 (c_ipack + curLoc, gribLen, &curLoc, DSF, grib_Data,
2082                        meta, f_bms, bitmap, unitM, unitB) != 0) {
2083       free (bitmap);
2084       preErrSprintf ("Inside ReadGrib1Record\n");
2085       return -4;
2086    }
2087    if (f_bms) {
2088       free (bitmap);
2089    }
2090 
2091    GRIB1_Table3LookUp (&(meta->pds1), &(meta->shortFstLevel),
2092                        &(meta->longFstLevel));
2093 /*   printf ("%s .. %s\n", meta->shortFstLevel, meta->longFstLevel);*/
2094 
2095 /*
2096    strftime (meta->refTime, 20, "%Y%m%d%H%M",
2097              gmtime (&(meta->pds1.refTime)));
2098 */
2099    Clock_Print (meta->refTime, 20, meta->pds1.refTime, "%Y%m%d%H%M", 0);
2100 
2101 /*
2102    strftime (meta->validTime, 20, "%Y%m%d%H%M",
2103              gmtime (&(meta->pds1.validTime)));
2104 */
2105    Clock_Print (meta->validTime, 20, meta->pds1.validTime, "%Y%m%d%H%M", 0);
2106 
2107    double deltaTime = meta->pds1.validTime - meta->pds1.refTime;
2108    if (deltaTime >= std::numeric_limits<sInt4>::max()) {
2109        printf ("Clamped deltaTime.  Was %lf\n", deltaTime);
2110        deltaTime = std::numeric_limits<sInt4>::max();
2111    }
2112    if (deltaTime <= std::numeric_limits<sInt4>::min()) {
2113        printf ("Clamped deltaTime.  Was %lf\n", deltaTime);
2114        deltaTime = std::numeric_limits<sInt4>::min();
2115    }
2116    meta->deltTime = static_cast<sInt4>(deltaTime);
2117 
2118    /* Read section 5.  If it is "7777" == 926365495 we are done. */
2119    if (curLoc == gribLen) {
2120       printf ("Warning: either gribLen did not account for section 5, or "
2121               "section 5 is missing\n");
2122       return 0;
2123    }
2124    if (curLoc + 4 != gribLen) {
2125       errSprintf ("Invalid number of bytes for the end of the message.\n");
2126       return -5;
2127    }
2128    memcpy (&li_temp, c_ipack + curLoc, 4);
2129    if (li_temp != 926365495L) {
2130       errSprintf ("Did not find the end of the message.\n");
2131       return -5;
2132    }
2133 
2134    return 0;
2135 }
2136 
2137 /*****************************************************************************
2138  * main() --
2139  *
2140  * Arthur Taylor / MDL
2141  *
2142  * PURPOSE
2143  *   To test the capabilities of this module, and give an example as to how
2144  * ReadGrib1Record expects to be called.
2145  *
2146  * ARGUMENTS
2147  * argc = The number of arguments on the command line. (Input)
2148  * argv = The arguments on the command line. (Input)
2149  *
2150  * FILES/DATABASES:
2151  *   A GRIB1 file.
2152  *
2153  * RETURNS: int
2154  *  0 = OK
2155  *
2156  * HISTORY
2157  *   4/2003 Arthur Taylor (MDL/RSIS): Created
2158  *   6/2003 Matthew T. Kallio (matt@wunderground.com):
2159  *          "wmo" dimension increased to WMO_HEADER_LEN + 1 (for '\0' char)
2160  *
2161  * NOTES
2162  *****************************************************************************
2163  */
2164 #ifdef DEBUG_DEGRIB1
2165 int main (int argc, char **argv)
2166 {
2167    VSILFILE * grib_fp;       /* The opened grib2 file for input. */
2168    char *buff = nullptr;
2169    uInt4 buffLen = 0;
2170    sInt4 sect0[SECT0LEN_WORD] = { 0 }; /* Holds the current Section 0. */
2171    uInt4 gribLen;       /* Length of the current GRIB message. */
2172    char *msg;
2173    int version;
2174    sChar f_unit = 0;
2175    double *grib_Data;
2176    uInt4 grib_DataLen;
2177    grib_MetaData meta;
2178 
2179    double majEarth = 0.0;  // -radEarth if < 6000 ignore, otherwise use this
2180                            // to override the radEarth in the GRIB1 or GRIB2
2181                            // message.  Needed because NCEP uses 6371.2 but
2182                            // GRIB1 could only state 6367.47.
2183    double minEarth = 0.0;  // -minEarth if < 6000 ignore, otherwise use this
2184                            // to override the minEarth in the GRIB1 or GRIB2
2185                            // message.
2186 
2187 
2188    IS_dataType is;      /* Un-parsed meta data for this GRIB2 message. As
2189                          * well as some memory used by the unpacker. */
2190 
2191    if ((grib_fp = VSIFOpenL (argv[1], "rb")) == NULL) {
2192       printf ("Problems opening %s for read\n", argv[1]);
2193       return 1;
2194    }
2195    IS_Init (&is);
2196    MetaInit (&meta);
2197 
2198    if (ReadSECT0 (grib_fp, &buff, &buffLen, -1, sect0, &gribLen, &version) < 0) {
2199       VSIFCloseL(grib_fp);
2200       free(buff);
2201       msg = errSprintf (NULL);
2202       printf ("%s\n", msg);
2203       return -1;
2204    }
2205    free(buff);
2206 
2207    grib_DataLen = 0;
2208    grib_Data = NULL;
2209    if (version == 1) {
2210       meta.GribVersion = version;
2211       ReadGrib1Record (grib_fp, f_unit, &grib_Data, &grib_DataLen, &meta,
2212                        &is, sect0, gribLen, majEarth, minEarth);
2213    }
2214 
2215    MetaFree (&meta);
2216    IS_Free (&is);
2217    free (grib_Data);
2218    VSIFCloseL(grib_fp);
2219    return 0;
2220 }
2221 #endif
2222