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, ¢er, &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, ¢er, &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