OpenCPN Partial API docs
Loading...
Searching...
No Matches
grib_v2_record.cpp
Go to the documentation of this file.
1/**********************************************************************
2zyGrib: meteorological GRIB file viewer
3Copyright (C) 2008 - Jacques Zaninetti - http://www.zygrib.org
4
5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation, either version 3 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program. If not, see <http://www.gnu.org/licenses/>.
17***********************************************************************/
18
25/*
26** File: unpackgrib2.c
27**
28** Author: Bob Dattore
29** NCAR/DSS
30** dattore@ucar.edu
31** (303) 497-1825
32** latest
33** 14 Aug 2015:
34** DRS Template 5.3 (complex packing and spatial differencing)
35
36 copyright ?
37*/
38
39#define __STDC_LIMIT_MACROS
40
41#include "wx/wxprec.h"
42
43#ifndef WX_PRECOMP
44#include "wx/wx.h"
45#endif
46
47#include <stdlib.h>
48
49#include "grib_v2_record.h"
50
51#include <vector>
52
53#include <libaec.h>
54
55#ifdef JASPER
56#include <jasper/jasper.h>
57#endif
58
59const double GRIB_MISSING_VALUE = GRIB_NOTDEF;
60
62public:
63 int proc_code;
64 int incr_type;
65 int time_unit;
66 int time_length;
67 int incr_unit;
68 int incr_length;
69};
70
72public:
73 GRIBMetadata() : bitmap(nullptr), bms(nullptr) {
74 stat_proc.t = nullptr;
75 lvl1_type = 0;
76 lvl2_type = 0;
77 lvl1 = 0.;
78 lvl2 = 0.;
79 };
80
82 delete[] stat_proc.t;
83 delete[] bitmap;
84 delete[] bms;
85 };
86
87 int gds_templ_num;
88
89 int earth_shape;
90 unsigned char
91 earth_sphere_scale_factor; // Scale factor of radius of spherical Earth
92 int earth_sphere_scale_value; // Scale value of radius of spherical Earth
93
94 unsigned char earth_major_scale_factor; // Scale factor of major axis of
95 // oblate spheroid Earth
96 int earth_major_scale_value; // Scaled value of major axis of oblate spheroid
97 // Earth
98
99 unsigned char earth_minor_scale_factor; // Scale factor of minor axis of
100 // oblate spheroid Earth
101 int earth_minor_scale_value; // Scaled value of minor axis of oblate spheroid
102 // Earth
103
104 int nx, ny;
105 double slat, slon, latin1, latin2, splat, splon;
106 double latD;
107 union {
108 double elat;
109 double lad;
110 } lats;
111 union {
112 double elon;
113 double lov;
114 } lons;
115 union {
116 double loinc;
117 double dxinc;
118 } xinc;
119 union {
120 double lainc;
121 double dyinc;
122 } yinc;
123 int rescomp, scan_mode, proj_flag;
124 int pds_templ_num;
125 int param_cat, param_num, gen_proc, time_unit, fcst_time;
126 int ens_type, perturb_num, derived_fcst_code, nfcst_in_ensemble;
127 int lvl1_type, lvl2_type;
128 double lvl1, lvl2;
129 struct {
130 int eyr, emo, edy, etime;
131 int num_ranges, nmiss;
132 GRIBStatproc *t;
133 } stat_proc;
134 struct {
135 int stat_proc, type, num_points;
136 } spatial_proc;
137 struct {
138 int split_method, miss_val_mgmt;
139 unsigned int num_groups;
140 float primary_miss_sub, secondary_miss_sub;
141 struct {
142 int ref, pack_width;
143 } width;
144 struct {
145 unsigned int ref, incr, last, pack_width;
146 } length;
147 struct {
148 unsigned int order, order_vals_width;
149 } spatial_diff;
150 } complex_pack;
151 struct {
152 int flags, block_size, rsi;
153 } ccsds;
154 int drs_templ_num;
155 int precision;
156 float R;
157 int E, D, num_packed, pack_width, orig_val_type;
158 int bms_ind;
159 unsigned char *bitmap;
161 zuchar *bms;
162 int bmssize;
163};
164
166public:
167 GRIB2Grid() : gridpoints(nullptr) {};
168 ~GRIB2Grid() { delete[] gridpoints; };
169
170 double *gridpoints;
171};
172
174public:
175 GRIBMessage() : buffer(nullptr) {};
176 ~GRIBMessage() { delete[] buffer; };
177 unsigned char *buffer;
178 int offset; /* offset in bytes to next GRIB2 section */
179 int total_len, disc, ed_num;
180 int center_id, sub_center_id, table_ver, local_table_ver, ref_time_type;
181 int yr, mo, dy, time;
182 int prod_status, data_type;
183 GRIBMetadata md;
184 size_t num_grids;
185 GRIB2Grid grids;
186};
187
188#ifdef JASPER
189static int dec_jpeg2000(char *injpc, int bufsize, int *outfld)
190/*$$$ SUBPROGRAM DOCUMENTATION BLOCK
191 * . . . .
192 * SUBPROGRAM: dec_jpeg2000 Decodes JPEG2000 code stream
193 * PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-12-02
194 *
195 * ABSTRACT: This Function decodes a JPEG2000 code stream specified in the
196 * JPEG2000 Part-1 standard (i.e., ISO/IEC 15444-1) using JasPer
197 * Software version 1.500.4 (or 1.700.2) written by the University of British
198 * Columbia and Image Power Inc, and others.
199 * JasPer is available at http://www.ece.uvic.ca/~mdadams/jasper/.
200 *
201 * PROGRAM HISTORY LOG:
202 * 2002-12-02 Gilbert
203 *
204 * USAGE: int dec_jpeg2000(char *injpc,int bufsize,int *outfld)
205 *
206 * INPUT ARGUMENTS:
207 * injpc - Input JPEG2000 code stream.
208 * bufsize - Length (in bytes) of the input JPEG2000 code stream.
209 *
210 * OUTPUT ARGUMENTS:
211 * outfld - Output matrix of grayscale image values.
212 *
213 * RETURN VALUES :
214 * 0 = Successful decode
215 * -2 = no memory Error.
216 * -3 = Error decode jpeg2000 code stream.
217 * -5 = decoded image had multiple color components.
218 * Only grayscale is expected.
219 *
220 * REMARKS:
221 *
222 * Requires JasPer Software version 1.500.4 or 1.700.2
223 *
224 * ATTRIBUTES:
225 * LANGUAGE: C
226 * MACHINE: IBM SP
227 *
228 *$$$*/
229
230{
231 int ier;
232 int i, j, k;
233 jas_image_t *image = nullptr;
234 jas_stream_t *jpcstream;
235 jas_image_cmpt_t *pcmpt;
236 char *opts = nullptr;
237 jas_matrix_t *data;
238
239 // jas_init();
240
241 ier = 0;
242 //
243 // Create jas_stream_t containing input JPEG200 codestream in memory.
244 //
245
246 jpcstream = jas_stream_memopen(injpc, bufsize);
247 if (jpcstream == nullptr) {
248 printf(" dec_jpeg2000: no memory\n");
249 return -2;
250 }
251 //
252 // Decode JPEG200 codestream into jas_image_t structure.
253 //
254 image = jpc_decode(jpcstream, opts);
255 if (image == nullptr) {
256 printf(" jpc_decode return = %d \n", ier);
257 return -3;
258 }
259
260 pcmpt = image->cmpts_[0];
261
262 // Expecting jpeg2000 image to be grayscale only.
263 // No color components.
264 //
265 if (image->numcmpts_ != 1) {
266 printf("dec_jpeg2000: Found color image. Grayscale expected.\n");
267 return (-5);
268 }
269
270 //
271 // Create a data matrix of grayscale image values decoded from
272 // the jpeg2000 codestream.
273 //
274 data = jas_matrix_create(jas_image_height(image), jas_image_width(image));
275 jas_image_readcmpt(image, 0, 0, 0, jas_image_width(image),
276 jas_image_height(image), data);
277 //
278 // Copy data matrix to output integer array.
279 //
280 k = 0;
281 for (i = 0; i < pcmpt->height_; i++)
282 for (j = 0; j < pcmpt->width_; j++) outfld[k++] = data->rows_[i][j];
283 //
284 // Clean up JasPer work structures.
285 //
286 jas_matrix_destroy(data);
287 ier = jas_stream_close(jpcstream);
288 jas_image_destroy(image);
289
290 return 0;
291}
292#endif
293
294static unsigned int uint2(unsigned char const *p) { return (p[0] << 8) + p[1]; }
295
296static unsigned int uint4(unsigned const char *p) {
297 return ((p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]);
298}
299
300static int int2(unsigned const char *p) {
301 int i;
302 if ((p[0] & 0x80)) {
303 i = -(((p[0] & 0x7f) << 8) + p[1]);
304 } else {
305 i = (p[0] << 8) + p[1];
306 }
307 return i;
308}
309
310static int int4(unsigned const char *p) {
311 int i;
312 if ((p[0] & 0x80)) {
313 i = -(((p[0] & 0x7f) << 24) + (p[1] << 16) + (p[2] << 8) + p[3]);
314 } else {
315 i = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
316 }
317 return i;
318}
319
320static float ieee2flt(unsigned const char *ieee) {
321 double fmant;
322 int exp;
323
324 if ((ieee[0] & 127) == 0 && ieee[1] == 0 && ieee[2] == 0 && ieee[3] == 0)
325 return (float)0.0;
326
327 exp = ((ieee[0] & 127) << 1) + (ieee[1] >> 7);
328 fmant = (double)((int)ieee[3] + (int)(ieee[2] << 8) +
329 (int)((ieee[1] | 128) << 16));
330 if (ieee[0] & 128) fmant = -fmant;
331
332 return (float)(ldexp(fmant, (int)(exp - 128 - 22)));
333}
334
335static inline void getBits(unsigned const char *buf, int *loc, size_t first,
336 size_t nbBits) {
337 if (nbBits == 0) {
338 // x >> 32 is undefined behavior, on x86 it returns x
339 *loc = 0;
340 return;
341 }
342
343 zuint oct = first / 8;
344 zuint bit = first % 8;
345
346 zuint val = (buf[oct] << 24) + (buf[oct + 1] << 16) + (buf[oct + 2] << 8) +
347 (buf[oct + 3]);
348 val = val << bit;
349 val = val >> (32 - nbBits);
350 *loc = val;
351}
352
353//-------------------------------------------------------------------------------
354// Lecture depuis un fichier
355//-------------------------------------------------------------------------------
356static void unpackIDS(GRIBMessage *grib_msg) {
357 int length;
358 int hh, mm, ss;
359 size_t ofs = grib_msg->offset / 8;
360 unsigned char *b = grib_msg->buffer + ofs;
361
362 length = uint4(b); /* length of the IDS */
363
364 grib_msg->center_id = uint2(b + 5); /* center ID */
365 grib_msg->sub_center_id = uint2(b + 7); /* sub-center ID */
366 grib_msg->table_ver = b[9]; /* table version */
367 grib_msg->local_table_ver = b[10]; /* local table version */
368 grib_msg->ref_time_type = b[11]; /* significance of reference time */
369 grib_msg->yr = uint2(b + 12); /* year */
370 grib_msg->mo = b[14]; /* month */
371 grib_msg->dy = b[15]; /* day */
372 hh = b[16]; /* hours */
373 mm = b[17]; /* minutes */
374 ss = b[18]; /* seconds */
375 grib_msg->time = hh * 10000 + mm * 100 + ss;
376 grib_msg->prod_status = b[19]; /* production status */
377 grib_msg->data_type = b[20]; /* type of data */
378 grib_msg->offset += length * 8;
379}
380
381static bool unpackLUS(GRIBMessage *grib_msg) { return true; }
382
383static void parse_earth(GRIBMessage *grib_msg) {
384 size_t ofs = grib_msg->offset / 8;
385 unsigned char *b = grib_msg->buffer + ofs;
386
387 grib_msg->md.earth_shape = b[14]; // shape of the earth
388
389 grib_msg->md.earth_sphere_scale_factor =
390 b[15]; // Scale factor of radius of spherical Earth
391 grib_msg->md.earth_sphere_scale_value =
392 uint4(b + 16); // Scale value of radius of spherical Earth
393
394 grib_msg->md.earth_major_scale_factor =
395 b[20]; // Scale factor of major axis of oblate spheroid Earth
396 grib_msg->md.earth_major_scale_value =
397 uint4(b + 21); // Scaled value of major axis of oblate spheroid Earth
398
399 grib_msg->md.earth_minor_scale_factor =
400 b[25]; // Scale factor of minor axis of oblate spheroid Earth
401 grib_msg->md.earth_minor_scale_value =
402 uint4(b + 26); // Scaled value of minor axis of oblate spheroid Earth
403}
404
405static bool unpackGDS(GRIBMessage *grib_msg) {
406 int src, num_in_list;
407 size_t ofs = grib_msg->offset / 8;
408 unsigned char *b = grib_msg->buffer + ofs;
409
410 src = b[5]; /* source of grid definition */
411 if (src != 0) {
412 fprintf(stderr, "Don't recognize predetermined grid definitions");
413 return false;
414 }
415
416 num_in_list = b[10]; /* quasi-regular grid indication */
417 if (num_in_list > 0) {
418 fprintf(stderr, "Unable to unpack quasi-regular grids");
419 return false;
420 }
421
422 /* grid definition template number Table 3.1 */
423 grib_msg->md.gds_templ_num = uint2(b + 12);
424 switch (grib_msg->md.gds_templ_num) {
425 case 0: /* Latitude/Longitude Also called Equidistant Cylindrical or Plate
426 Caree */
427 case 40: /* Gaussian Latitude/Longitude */
428 parse_earth(grib_msg);
429
430 grib_msg->md.nx = uint4(b + 30); /* number of latitudes */
431 grib_msg->md.ny = uint4(b + 34); /* number of longitudes */
432
433 grib_msg->md.slat =
434 int4(b + 46) / 1000000.; /* latitude of first gridpoint */
435 grib_msg->md.slon =
436 int4(b + 50) / 1000000.; /* longitude of first gridpoint */
437
438 grib_msg->md.rescomp = b[54]; /* resolution and component flags */
439
440 grib_msg->md.lats.elat =
441 int4(b + 55) / 1000000.; /* latitude of last gridpoint */
442 grib_msg->md.lons.elon =
443 int4(b + 59) / 1000000.; /* longitude of last gridpoint */
444
445 grib_msg->md.xinc.loinc =
446 uint4(b + 63) / 1000000.; /* longitude increment */
447
448 if (grib_msg->md.gds_templ_num == 0)
449 grib_msg->md.yinc.lainc =
450 uint4(b + 67) / 1000000.; /* latitude increment */
451
452 grib_msg->md.scan_mode = b[71]; /* scanning mode flag */
453 break;
454 case 10: /* Mercator */
455 parse_earth(grib_msg);
456
457 grib_msg->md.nx = uint4(b + 30); /* number of points along a parallel */
458 grib_msg->md.ny = uint4(b + 34); /* number of points along a meridian */
459
460 grib_msg->md.slat =
461 int4(b + 38) / 1000000.; /* latitude of first gridpoint */
462 grib_msg->md.slon =
463 int4(b + 42) / 1000000.; /* longitude of first gridpoint */
464
465 grib_msg->md.rescomp = b[46]; /* resolution and component flags */
466 grib_msg->md.latD =
467 int4(b + 47) /
468 1000000.; /* latitude at which the Mercator projection intersects the
469 Earth (Latitude where Di and Dj are specified) */
470
471 grib_msg->md.lats.elat =
472 int4(b + 51) / 1000000.; /* latitude of last gridpoint */
473 grib_msg->md.lons.elon =
474 int4(b + 55) / 1000000.; /* longitude of last gridpoint */
475
476 grib_msg->md.scan_mode = b[59]; /* scanning mode flag */
477
478 grib_msg->md.xinc.loinc = uint4(b + 64) / 1000.; /* longitude increment */
479 grib_msg->md.yinc.lainc = uint4(b + 68) / 1000.; /* latitude increment */
480 break;
481 case 30: /* Lambert conformal grid */
482 parse_earth(grib_msg);
483
484 grib_msg->md.nx = uint4(b + 30); /* number of points along a parallel */
485 grib_msg->md.ny = uint4(b + 34); /* number of points along a meridian */
486
487 grib_msg->md.slat =
488 int4(b + 38) / 1000000.; /* latitude of first gridpoint */
489 grib_msg->md.slon =
490 int4(b + 42) / 1000000.; /* longitude of first gridpoint */
491
492 grib_msg->md.rescomp = b[46]; /* resolution and component flags */
493
494 grib_msg->md.lats.lad = int4(b + 47) / 1000000.; /* LaD */
495 grib_msg->md.lons.lov = int4(b + 51) / 1000000.; /* LoV */
496
497 grib_msg->md.xinc.dxinc =
498 int4(b + 55) / 1000.; /* x-direction increment */
499 grib_msg->md.yinc.dyinc =
500 int4(b + 59) / 1000.; /* y-direction increment */
501
502 grib_msg->md.proj_flag = b[63]; /* projection center flag */
503 grib_msg->md.scan_mode = b[64]; /* scanning mode flag */
504
505 grib_msg->md.latin1 = int4(b + 65) / 1000000.; /* latin1 */
506 grib_msg->md.latin2 = int4(b + 69) / 1000000.; /* latin2 */
507
508 grib_msg->md.splat =
509 int4(b + 73) / 1000000.; /* latitude of southern pole of projection */
510 grib_msg->md.splon =
511 int4(b + 77) /
512 1000000.; /* longitude of southern pole of projection */
513 break;
514 default:
515 fprintf(stderr, "Grid template %d is not understood\n",
516 grib_msg->md.gds_templ_num);
517 return false;
518 }
519 return true;
520}
521
522static void unpack_stat_proc(GRIBMessage *grib_msg, unsigned const char *b) {
523 int hh, mm, ss;
524 size_t n, off;
525
526 grib_msg->md.stat_proc.eyr = uint2(b);
527 grib_msg->md.stat_proc.emo = b[2];
528 grib_msg->md.stat_proc.edy = b[3];
529 hh = b[4];
530 mm = b[5];
531 ss = b[6];
532 grib_msg->md.stat_proc.etime = hh * 10000 + mm * 100 + ss;
533
534 grib_msg->md.stat_proc.num_ranges =
535 b[7]; /* number of time range specifications */
536 grib_msg->md.stat_proc.nmiss =
537 uint4(b + 8); /* number of values missing from process */
538
539 if (grib_msg->md.stat_proc.t != 0) {
540 delete[] grib_msg->md.stat_proc.t;
541 }
542 grib_msg->md.stat_proc.t =
543 new GRIBStatproc[grib_msg->md.stat_proc.num_ranges];
544 off = 12;
545 for (n = 0; n < (size_t)grib_msg->md.stat_proc.num_ranges; n++) {
546 grib_msg->md.stat_proc.t[n].proc_code = b[off];
547 grib_msg->md.stat_proc.t[n].incr_type = b[off + 1];
548 grib_msg->md.stat_proc.t[n].time_unit = b[off + 2];
549 grib_msg->md.stat_proc.t[n].time_length = uint4(b + off + 3);
550 grib_msg->md.stat_proc.t[n].incr_unit = b[off + 7];
551 grib_msg->md.stat_proc.t[n].incr_length = uint4(b + off + 8);
552 off += 12;
553 }
554}
555
556// Section 4: Product Definition Section
557static bool unpackPDS(GRIBMessage *grib_msg) {
558 int num_coords, factor;
559 size_t ofs = grib_msg->offset / 8;
560 unsigned char *b = grib_msg->buffer + ofs;
561
562 num_coords = uint2(b + 5); /* indication of hybrid coordinate system */
563 if (num_coords > 0) {
564 fprintf(stderr, "Unable to decode hybrid coordinates");
565 return false;
566 }
567
568 grib_msg->md.pds_templ_num =
569 uint2(b + 7); /* product definition template number */
570 grib_msg->md.stat_proc.num_ranges = 0;
571 switch (grib_msg->md.pds_templ_num) {
572 case 0:
573 case 1:
574 case 2:
575 case 8: // Average, accumulation, extreme values
576 case 11:
577 case 12:
578 case 15:
579 grib_msg->md.ens_type = -1;
580 grib_msg->md.derived_fcst_code = -1;
581 grib_msg->md.spatial_proc.type = -1;
582 grib_msg->md.param_cat = b[9]; /* parameter category */
583 grib_msg->md.param_num = b[10]; /* parameter number */
584 grib_msg->md.gen_proc = b[11]; /* generating process */
585
586 grib_msg->md.time_unit = b[17]; /* time range indicator*/
587 grib_msg->md.fcst_time = uint4(b + 18); /* forecast time */
588
589 grib_msg->md.lvl1_type = b[22]; /* type of first level */
590 factor = b[23]; /* value of first level */
591 grib_msg->md.lvl1 = int4(b + 24) / pow(10., (double)factor);
592
593 grib_msg->md.lvl2_type = b[28]; /* type of second level */
594 factor = b[29]; /* value of second level */
595 grib_msg->md.lvl2 = int4(b + 30) / pow(10., (double)factor);
596
597 switch (grib_msg->md.pds_templ_num) {
598 case 1:
599 case 11:
600 grib_msg->md.ens_type = b[34];
601 grib_msg->md.perturb_num = b[35];
602 grib_msg->md.nfcst_in_ensemble = b[36];
603
604 switch (grib_msg->md.pds_templ_num) {
605 case 11:
606 unpack_stat_proc(grib_msg, b + 37);
607 break;
608 }
609 break;
610 case 2:
611 case 12:
612 grib_msg->md.derived_fcst_code = b[34];
613 grib_msg->md.nfcst_in_ensemble = b[35];
614
615 switch (grib_msg->md.pds_templ_num) {
616 case 12:
617 unpack_stat_proc(grib_msg, b + 36);
618 break;
619 }
620 break;
621 case 8:
622 unpack_stat_proc(grib_msg, b + 34);
623 break;
624 case 15:
625 grib_msg->md.spatial_proc.stat_proc = b[34];
626 grib_msg->md.spatial_proc.type = b[35];
627 grib_msg->md.spatial_proc.num_points = b[36];
628 break;
629 }
630 break;
631 default:
632 fprintf(stderr, "Product Definition Template %d is not understood\n",
633 grib_msg->md.pds_templ_num);
634 return false;
635 }
636 return true;
637}
638
639// Section 5: Data Representation Section
640static bool unpackDRS(GRIBMessage *grib_msg) {
641 size_t ofs = grib_msg->offset / 8;
642 unsigned char *b = grib_msg->buffer + ofs;
643
644 grib_msg->md.num_packed = uint4(b + 5); /* number of packed values */
645 grib_msg->md.drs_templ_num =
646 uint2(b + 9); /* data representation template number */
647
648 switch (grib_msg->md.drs_templ_num) { // Table 5.0
649 case 4: // Grid Point Data - Simple Packing
650 grib_msg->md.precision = b[11];
651 break;
652 case 0: // Grid Point Data - Simple Packing
653 case 2: // Grid Point Data - Complex Packing
654 case 3: // Grid Point Data - Complex Packing and Spatial Differencing
655 case 42: // Grid Point Data - CCSDS Recommended Lossless Compression
656#ifdef JASPER
657 case 40: // Grid Point Data - JPEG2000 Compression
658 case 40000:
659#endif
660 /* cf
661 * http://www.wmo.int/pages/prog/www/WMOCodes/Guides/GRIB/GRIB2_062006.pdf
662 * p. 36*/
663 grib_msg->md.R = ieee2flt(b + 11);
664 grib_msg->md.E = int2(b + 15);
665 grib_msg->md.D = int2(b + 17);
666 grib_msg->md.R /= pow(10., grib_msg->md.D);
667
668 grib_msg->md.pack_width = b[19];
669 grib_msg->md.orig_val_type = b[20];
670
671 if (grib_msg->md.drs_templ_num == 3 || grib_msg->md.drs_templ_num == 2) {
672 grib_msg->md.complex_pack.split_method = b[21];
673 grib_msg->md.complex_pack.miss_val_mgmt = b[22];
674 if (grib_msg->md.orig_val_type == 0) { // Table 5.1
675 grib_msg->md.complex_pack.primary_miss_sub = ieee2flt(b + 23);
676 grib_msg->md.complex_pack.secondary_miss_sub = ieee2flt(b + 27);
677 } else if (grib_msg->md.orig_val_type == 1) {
678 grib_msg->md.complex_pack.primary_miss_sub = uint4(b + 23);
679 grib_msg->md.complex_pack.secondary_miss_sub = uint4(b + 27);
680 } else {
681 fprintf(stderr,
682 "Unable to decode missing value substitutes for original "
683 "value type %d\n",
684 grib_msg->md.orig_val_type);
685 return false;
686 }
687 grib_msg->md.complex_pack.num_groups = uint4(b + 31);
688
689 grib_msg->md.complex_pack.width.ref = b[35];
690 grib_msg->md.complex_pack.width.pack_width = b[36];
691
692 grib_msg->md.complex_pack.length.ref = uint4(b + 37);
693 grib_msg->md.complex_pack.length.incr = b[41];
694 grib_msg->md.complex_pack.length.last = uint4(b + 42);
695 grib_msg->md.complex_pack.length.pack_width = b[46];
696 }
697 if (grib_msg->md.drs_templ_num == 42) {
698 grib_msg->md.ccsds.flags = b[21];
699 grib_msg->md.ccsds.block_size = b[22];
700 grib_msg->md.ccsds.rsi = uint2(b + 23);
701 }
702 if (grib_msg->md.drs_templ_num == 3) {
703 grib_msg->md.complex_pack.spatial_diff.order = b[47];
704 grib_msg->md.complex_pack.spatial_diff.order_vals_width = b[48];
705 } else {
706 grib_msg->md.complex_pack.spatial_diff.order = 0;
707 grib_msg->md.complex_pack.spatial_diff.order_vals_width = 0;
708 }
709 break;
710 default:
711 fprintf(stderr, "Data template %d is not understood\n",
712 grib_msg->md.drs_templ_num);
713 return false;
714 }
715 return true;
716}
717
718// Section 6: Bit-Map Section
719static bool unpackBMS(GRIBMessage *grib_msg) {
720 int ind, len, n, bit;
721 size_t ofs = grib_msg->offset / 8;
722 unsigned char *b = grib_msg->buffer + ofs;
723
724 ind = b[5]; /* bit map indicator */
725 switch (ind) {
726 case 0: // A bit map applies to this product and is specified in this
727 // section.
728 len = uint4(b);
729 if (len < 7) return false;
730 len -= 6;
731 grib_msg->md.bmssize = len;
732 len *= 8;
733 delete[] grib_msg->md.bitmap;
734 delete[] grib_msg->md.bms;
735 grib_msg->md.bitmap = new unsigned char[len];
736 grib_msg->md.bms = new zuchar[grib_msg->md.bmssize];
737 memcpy(grib_msg->md.bms, b + 6, grib_msg->md.bmssize);
738 for (n = 0; n < len; n++) {
739 getBits(grib_msg->buffer, &bit, grib_msg->offset + 48 + n, 1);
740 grib_msg->md.bitmap[n] = bit;
741 }
742 break;
743 case 254: // A bit map previously defined in the same GRIB2 message applies
744 // to this product.
745 break;
746 case 255: // A bit map does not apply to this product.
747 delete[] grib_msg->md.bitmap;
748 grib_msg->md.bitmap = nullptr;
749 delete[] grib_msg->md.bms;
750 grib_msg->md.bms = nullptr;
751 grib_msg->md.bmssize = 0;
752 break;
753 default:
754 fprintf(stderr,
755 "This code is not currently set up to deal with predefined "
756 "bit-maps\n");
757 return false;
758 }
759 return true;
760}
761
762// Section 7: Data Section
763static bool unpackDS(GRIBMessage *grib_msg) {
764 int off, pval, l;
765 unsigned int n, m;
766
767 struct {
768 int *ref_vals, *widths;
769 int *lengths;
770 int *first_vals = 0, sign, omin;
771 long long miss_val, group_miss_val;
772 int max_length;
773 } groups;
774 float lastgp, D = pow(10., grib_msg->md.D), E = pow(2., grib_msg->md.E);
775
776 groups.omin = 0;
777 groups.first_vals = nullptr;
778
779 off = grib_msg->offset + 40;
780 int npoints = grib_msg->md.ny * grib_msg->md.nx;
781 switch (grib_msg->md.drs_templ_num) {
782 case 0:
783 grib_msg->grids.gridpoints = new double[npoints];
784 for (l = 0; l < npoints; l++) {
785 if (grib_msg->md.bitmap == nullptr || grib_msg->md.bitmap[l] == 1) {
786 getBits(grib_msg->buffer, &pval, off, grib_msg->md.pack_width);
787 grib_msg->grids.gridpoints[l] = grib_msg->md.R + pval * E / D;
788 off += grib_msg->md.pack_width;
789 } else
790 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
791 }
792 break;
793 case 3:
794 if (grib_msg->md.complex_pack.num_groups > 0) {
795 if (grib_msg->md.complex_pack.spatial_diff.order) {
796 groups.first_vals =
797 new int[grib_msg->md.complex_pack.spatial_diff.order];
798 for (n = 0; n < grib_msg->md.complex_pack.spatial_diff.order; ++n) {
799 getBits(
800 grib_msg->buffer, &groups.first_vals[n], off,
801 grib_msg->md.complex_pack.spatial_diff.order_vals_width * 8);
802 off += grib_msg->md.complex_pack.spatial_diff.order_vals_width * 8;
803 }
804 }
805 getBits(grib_msg->buffer, &groups.sign, off, 1);
806 getBits(
807 grib_msg->buffer, &groups.omin, off + 1,
808 grib_msg->md.complex_pack.spatial_diff.order_vals_width * 8 - 1);
809 if (groups.sign == 1) {
810 groups.omin = -groups.omin;
811 }
812 off += grib_msg->md.complex_pack.spatial_diff.order_vals_width * 8;
813 }
814 // fall through
815 case 2:
816 grib_msg->grids.gridpoints = new double[npoints];
817 if (grib_msg->md.complex_pack.num_groups == 0) {
818 for (l = 0; l < npoints; ++l) {
819 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
820 }
821 break;
822 }
823 if (grib_msg->md.complex_pack.miss_val_mgmt > 0) {
824 groups.miss_val = pow(2., grib_msg->md.pack_width) - 1;
825 } else {
826 groups.miss_val = GRIB_MISSING_VALUE;
827 }
828
829 groups.ref_vals = new int[grib_msg->md.complex_pack.num_groups];
830 groups.widths = new int[grib_msg->md.complex_pack.num_groups];
831 groups.lengths = new int[grib_msg->md.complex_pack.num_groups];
832
833 for (n = 0; n < grib_msg->md.complex_pack.num_groups; ++n) {
834 getBits(grib_msg->buffer, &groups.ref_vals[n], off,
835 grib_msg->md.pack_width);
836 off += grib_msg->md.pack_width;
837 }
838 off = (off + 7) & ~7; // byte boundary padding
839
840 for (n = 0; n < grib_msg->md.complex_pack.num_groups; ++n) {
841 getBits(grib_msg->buffer, &groups.widths[n], off,
842 grib_msg->md.complex_pack.width.pack_width);
843 groups.widths[n] += grib_msg->md.complex_pack.width.ref;
844 off += grib_msg->md.complex_pack.width.pack_width;
845 }
846 off = (off + 7) & ~7;
847
848 for (n = 0; n < grib_msg->md.complex_pack.num_groups; ++n) {
849 getBits(grib_msg->buffer, &groups.lengths[n], off,
850 grib_msg->md.complex_pack.length.pack_width);
851 off += grib_msg->md.complex_pack.length.pack_width;
852 }
853 off = (off + 7) & ~7;
854
855 groups.max_length = 0;
856 for (n = 0; n < grib_msg->md.complex_pack.num_groups - 1; ++n) {
857 groups.lengths[n] =
858 grib_msg->md.complex_pack.length.ref +
859 groups.lengths[n] * grib_msg->md.complex_pack.length.incr;
860 if (groups.lengths[n] > groups.max_length) {
861 groups.max_length = groups.lengths[n];
862 }
863 }
864 groups.lengths[n] = grib_msg->md.complex_pack.length.last;
865 if (groups.lengths[n] > groups.max_length) {
866 groups.max_length = groups.lengths[n];
867 }
868 // unpack the field of differences
869 for (n = 0, l = 0; n < grib_msg->md.complex_pack.num_groups; ++n) {
870 if (groups.widths[n] > 0) {
871 if (grib_msg->md.complex_pack.miss_val_mgmt > 0) {
872 groups.group_miss_val = pow(2., groups.widths[n]) - 1;
873 } else {
874 groups.group_miss_val = GRIB_MISSING_VALUE;
875 }
876 for (int i = 0; i < groups.lengths[n];) {
877 if (grib_msg->md.bitmap != nullptr && grib_msg->md.bitmap[l] == 0) {
878 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
879 } else {
880 getBits(grib_msg->buffer, &pval, off, groups.widths[n]);
881 off += groups.widths[n];
882 if (pval == groups.group_miss_val) {
883 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
884 } else {
885 grib_msg->grids.gridpoints[l] =
886 pval + groups.ref_vals[n] + groups.omin;
887 }
888 ++i;
889 }
890 ++l;
891 }
892 } else { // constant group XXX bitmap?
893 for (int i = 0; i < groups.lengths[n];) {
894 if (grib_msg->md.bitmap != nullptr && grib_msg->md.bitmap[l] == 0) {
895 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
896 } else {
897 if (groups.ref_vals[n] == groups.miss_val) {
898 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
899 } else {
900 grib_msg->grids.gridpoints[l] =
901 groups.ref_vals[n] + groups.omin;
902 }
903 ++i;
904 }
905 ++l;
906 }
907 }
908 }
909
910 for (; l < npoints; ++l) {
911 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
912 }
913
914 if (grib_msg->md.drs_templ_num == 3) {
915 if (groups.first_vals != nullptr) {
916 for (n = grib_msg->md.complex_pack.spatial_diff.order - 1; n > 0;
917 --n) {
918 lastgp = groups.first_vals[n] - groups.first_vals[n - 1];
919 for (l = 0, m = 0; l < grib_msg->md.nx * grib_msg->md.ny; ++l) {
920 if (grib_msg->grids.gridpoints[l] != GRIB_MISSING_VALUE) {
921 if (m >= grib_msg->md.complex_pack.spatial_diff.order) {
922 grib_msg->grids.gridpoints[l] += lastgp;
923 lastgp = grib_msg->grids.gridpoints[l];
924 }
925 ++m;
926 }
927 }
928 }
929 }
930 for (l = 0, m = 0, lastgp = 0; l < npoints; ++l) {
931 if (grib_msg->grids.gridpoints[l] != GRIB_MISSING_VALUE) {
932 if (m < grib_msg->md.complex_pack.spatial_diff.order) {
933 grib_msg->grids.gridpoints[l] =
934 grib_msg->md.R + groups.first_vals[m] * E / D;
935 lastgp = grib_msg->md.R * D / E + groups.first_vals[m];
936 } else {
937 lastgp += grib_msg->grids.gridpoints[l];
938 grib_msg->grids.gridpoints[l] = lastgp * E / D;
939 }
940 ++m;
941 }
942 }
943 delete[] groups.first_vals;
944 } else
945 for (l = 0; l < npoints; ++l) {
946 if (grib_msg->grids.gridpoints[l] != GRIB_MISSING_VALUE) {
947 grib_msg->grids.gridpoints[l] =
948 grib_msg->md.R + grib_msg->grids.gridpoints[l] * E / D;
949 }
950 }
951 delete[] groups.ref_vals;
952 delete[] groups.widths;
953 delete[] groups.lengths;
954 break;
955 case 4: {
956 // Grid point data - IEEE Floating Point Data
957 if (grib_msg->md.precision == 1) { // IEEE754 single precision
958 grib_msg->grids.gridpoints = new double[npoints];
959 for (int ll = 0; ll < npoints; ll++) {
960 if (grib_msg->md.bitmap == nullptr || grib_msg->md.bitmap[ll] == 1) {
961 grib_msg->grids.gridpoints[ll] =
962 ieee2flt(grib_msg->buffer + off / 8);
963 off += 32;
964 } else
965 grib_msg->grids.gridpoints[ll] = GRIB_MISSING_VALUE;
966 }
967 } else if (grib_msg->md.precision == 2) { // IEEE754 single precision
968 static const int one = 1;
969 bool const is_lsb = *((char *)&one) == 1;
970 grib_msg->grids.gridpoints = new double[npoints];
971 for (l = 0; l < npoints; l++) {
972 if (grib_msg->md.bitmap == nullptr || grib_msg->md.bitmap[l] == 1) {
973 double d;
974 if (is_lsb) {
975 unsigned char temp[8];
976 for (int j = 0; j < 8; j++) {
977 temp[j] = grib_msg->buffer[off / 8 + 7 - j];
978 }
979 memcpy(&d, temp, 8);
980 } else {
981 memcpy(&d, grib_msg->buffer + off / 8, 8);
982 }
983 grib_msg->grids.gridpoints[l] = d;
984 off += 64;
985 } else
986 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
987 }
988 } else {
989 fprintf(stderr,
990 "g2_unpack7: Invalid precision=%d for Data Section 5.4.\n",
991 grib_msg->md.precision);
992 return false;
993 }
994 } break;
995 case 42: {
996 int len;
997 getBits(grib_msg->buffer, &len, grib_msg->offset, 32);
998 if (len < 5) return false;
999 len -= 5;
1000 int nbits = grib_msg->md.pack_width;
1001 int flags = grib_msg->md.ccsds.flags;
1002 // Sample size in the decoded stream, cf. libaec docs (3 bytes only with
1003 // AEC_DATA_3BYTE).
1004 size_t nbytes = (nbits + 7) / 8;
1005 if (nbytes == 3 && !(flags & AEC_DATA_3BYTE)) nbytes = 4;
1006 size_t nvals = grib_msg->md.num_packed;
1007 std::vector<unsigned char> out(nvals * nbytes);
1008 if (nbits > 0 && len > 0 && nvals > 0) {
1009 aec_stream strm;
1010 strm.flags = flags;
1011 strm.bits_per_sample = nbits;
1012 strm.block_size = grib_msg->md.ccsds.block_size;
1013 strm.rsi = grib_msg->md.ccsds.rsi;
1014 strm.next_in = &grib_msg->buffer[grib_msg->offset / 8 + 5];
1015 strm.avail_in = len;
1016 strm.next_out = out.data();
1017 strm.avail_out = out.size();
1018 if (aec_buffer_decode(&strm) != AEC_OK) {
1019 erreur("CCSDS decoding failed (%d bits)", nbits);
1020 return false;
1021 }
1022 }
1023 grib_msg->grids.gridpoints = new double[npoints];
1024 size_t cnt = 0;
1025 for (l = 0; l < npoints; l++) {
1026 if ((grib_msg->md.bitmap == nullptr || grib_msg->md.bitmap[l] == 1) &&
1027 cnt < nvals) {
1028 const unsigned char *p = out.data() + cnt++ * nbytes;
1029 unsigned int v = 0;
1030 for (size_t k = 0; k < nbytes; k++)
1031 v |= (unsigned int)(flags & AEC_DATA_MSB ? p[k] : p[nbytes - 1 - k])
1032 << (8 * (nbytes - 1 - k));
1033 grib_msg->grids.gridpoints[l] = grib_msg->md.R + v * E / D;
1034 } else
1035 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
1036 }
1037 } break;
1038#ifdef JASPER
1039 case 40:
1040 case 40000:
1041 int len, *jvals, cnt;
1042 getBits(grib_msg->buffer, &len, grib_msg->offset, 32);
1043 if (len < 5) return false;
1044 len = len - 5;
1045 jvals = new int[npoints];
1046 grib_msg->grids.gridpoints = new double[npoints];
1047 if (len > 0)
1048 dec_jpeg2000((char *)&grib_msg->buffer[grib_msg->offset / 8 + 5], len,
1049 jvals);
1050 cnt = 0;
1051 for (l = 0; l < npoints; l++) {
1052 if (grib_msg->md.bitmap == nullptr || grib_msg->md.bitmap[l] == 1) {
1053 if (len == 0) jvals[cnt] = 0;
1054 grib_msg->grids.gridpoints[l] = grib_msg->md.R + jvals[cnt++] * E / D;
1055 } else
1056 grib_msg->grids.gridpoints[l] = GRIB_MISSING_VALUE;
1057 }
1058 delete[] jvals;
1059 break;
1060#endif
1061 default:
1062 erreur("Unknown packing %d", grib_msg->md.drs_templ_num);
1063 break;
1064 }
1065 return true;
1066}
1067
1068static zuchar GRBV2_TO_DATA(int productDiscipline, int dataCat, int dataNum) {
1069 zuchar ret = 255;
1070 // printf("search %d %d %d\n", productDiscipline, dataCat, dataNum);
1071 switch (productDiscipline) { // TABLE 4.2
1072 case 0: // Meteorological products
1073 switch (dataCat) {
1074 case 0: // Temperature
1075 switch (dataNum) {
1076 case 0:
1077 ret = GRB_TEMP;
1078 break; // DATA_TO_GRBV2[DATA_TEMP] = grb2DataType(0,0,0);
1079 case 2:
1080 ret = GRB_TPOT;
1081 break; // DATA_TO_GRBV2[DATA_TEMP_POT] = grb2DataType(0,0,2);
1082 case 4:
1083 ret = GRB_TMAX;
1084 break; // DATA_TO_GRBV2[DATA_TMAX] = grb2DataType(0,0,4);
1085 case 5:
1086 ret = GRB_TMIN;
1087 break; // DATA_TO_GRBV2[DATA_TMIN] = grb2DataType(0,0,5);
1088 case 6:
1089 ret = GRB_DEWPOINT;
1090 break; // DATA_TO_GRBV2[DATA_DEWPOINT] = grb2DataType(0,0,6);
1091 case 17:
1092 ret = GRB_WTMP; // Skin temperature [C] SFC="Ground or water
1093 // surface"
1094 break; // DATA_TO_GRBV2[DATA_DEWPOINT] = grb2DataType(0,0,17);
1095 }
1096 break;
1097 case 1: // dataCat Moisture
1098 switch (dataNum) {
1099 case 0:
1100 ret = GRB_HUMID_SPEC;
1101 break; // DATA_TO_GRBV2[DATA_HUMID_SPEC] = grb2DataType(0,1,0);
1102 case 1:
1103 ret = GRB_HUMID_REL;
1104 break; // DATA_TO_GRBV2[DATA_HUMID_REL] = grb2DataType(0,1,1);
1105 case 7:
1106 ret = GRB_PRECIP_RATE;
1107 break; // DATA_TO_GRBV2[DATA_PRECIP_RATE] = grb2DataType(0,1,7);
1108 case 49: // Total Water Precipitation (Meteo France Arome 0.01
1109 case 52: // Total precipitation rate kg m–2 s–1
1110 case 8:
1111 ret = GRB_PRECIP_TOT;
1112 break; // DATA_TO_GRBV2[DATA_PRECIP_TOT] = grb2DataType(0,1,8);
1113 case 11:
1114 ret = GRB_SNOW_DEPTH;
1115 break; // DATA_TO_GRBV2[DATA_SNOW_DEPTH] = grb2DataType(0,1,11);
1116 case 193:
1117 ret = GRB_FRZRAIN_CATEG;
1118 break; // DATA_TO_GRBV2[DATA_FRZRAIN_CATEG] =
1119 // grb2DataType(0,1,193);
1120 case 195:
1121 ret = GRB_SNOW_CATEG;
1122 break; // DATA_TO_GRBV2[DATA_SNOW_CATEG] = grb2DataType(0,1,195);
1123 }
1124 break;
1125 case 2: // dataCat Momentum
1126 switch (dataNum) {
1127 case 0:
1128 ret = GRB_WIND_DIR;
1129 break;
1130 case 1:
1131 ret = GRB_WIND_SPEED;
1132 break;
1133 case 2:
1134 ret = GRB_WIND_VX;
1135 break; // DATA_TO_GRBV2[DATA_WIND_VX] = grb2DataType(0,2,2);
1136 case 3:
1137 ret = GRB_WIND_VY;
1138 break; // DATA_TO_GRBV2[DATA_WIND_VY] = grb2DataType(0,2,3);
1139 case 22:
1140 ret = GRB_WIND_GUST;
1141 break; //
1142 }
1143 break;
1144 case 3: // dataCat mass
1145 switch (dataNum) {
1146 case 0:
1147 ret = GRB_PRESSURE;
1148 break; // DATA_TO_GRBV2[DATA_PRESSURE] = grb2DataType(0,3,0);
1149 case 1:
1150 ret = GRB_PRESSURE;
1151 break; // PRSMSL //DATA_TO_GRBV2[DATA_PRESSURE] =
1152 // grb2DataType(0,3,0);
1153 case 5:
1154 ret = GRB_GEOPOT_HGT;
1155 break; // DATA_TO_GRBV2[DATA_GEOPOT_HGT]= grb2DataType(0,3,5);
1156
1157 case 192:
1158 ret = GRB_PRESSURE;
1159 break; // DATA_TO_GRBV2[DATA_MSLET] = grb2DataType(0,3,192);
1160 }
1161 break;
1162 case 6: // dataCat
1163 switch (dataNum) {
1164 case 1:
1165 ret = GRB_CLOUD_TOT;
1166 break; // DATA_TO_GRBV2[DATA_CLOUD_TOT] = grb2DataType(0,6,1);
1167 }
1168 break;
1169 case 7: // dataCat
1170 switch (dataNum) {
1171 // case 7: ret = GRB_?; break // DATA_TO_GRBV2[DATA_CIN] =
1172 // grb2DataType(0,7,7);
1173 case 6:
1174 ret = GRB_CAPE;
1175 break; // DATA_TO_GRBV2[DATA_CAPE] = grb2DataType(0,7,6);
1176 }
1177 break;
1178 case 16: // Meteorological products, Forecast Radar Imagery category
1179 switch (dataNum) {
1180 case 196:
1181 ret = GRB_COMP_REFL;
1182 break; // = grb2DataType(0,16, 196);
1183 }
1184 break;
1185 }
1186 break;
1187 case 10: // productDiscipline Oceanographic products
1188 switch (dataCat) {
1189 case 0: // waves
1190#if 0
1191 switch (dataNum) {
1192 case 3: ret= GRB_WVHGT; break; //DATA_TO_GRBV2[DATA_WAVES_SIG_HGT_COMB] = grb2DataType(10,0,3);
1193 DATA_TO_GRBV2[DATA_WAVES_WND_DIR] = grb2DataType(10,0,4);
1194 DATA_TO_GRBV2[DATA_WAVES_WND_HGT] = grb2DataType(10,0,5);
1195 DATA_TO_GRBV2[DATA_WAVES_WND_PERIOD] = grb2DataType(10,0,6);
1196 DATA_TO_GRBV2[DATA_WAVES_SWL_DIR] = grb2DataType(10,0,7);
1197 DATA_TO_GRBV2[DATA_WAVES_SWL_HGT] = grb2DataType(10,0,8);
1198 DATA_TO_GRBV2[DATA_WAVES_SWL_PERIOD] = grb2DataType(10,0,9);
1199 DATA_TO_GRBV2[DATA_WAVES_PRIM_DIR] = grb2DataType(10,0,10);
1200 DATA_TO_GRBV2[DATA_WAVES_PRIM_PERIOD] = grb2DataType(10,0,11);
1201 DATA_TO_GRBV2[DATA_WAVES_SEC_DIR] = grb2DataType(10,0,12);
1202 DATA_TO_GRBV2[DATA_WAVES_SEC_PERIOD] = grb2DataType(10,0,13);
1203 }
1204#endif
1205
1206 switch (dataNum) {
1207 case 3:
1208 ret = GRB_HTSGW;
1209 break; // Significant Height of Combined Wind Waves and Swell
1210 case 4:
1211 ret = GRB_WVDIR;
1212 break; // Direction of Wind Waves
1213 case 5:
1214 ret = GRB_WVHGT;
1215 break; // Significant Height of Wind Waves
1216 case 6:
1217 ret = GRB_WVPER;
1218 break; // Mean Period of Wind Waves
1219 case 14:
1220 ret = GRB_DIR;
1221 break; // Direction of Combined Wind Waves and Swell
1222 case 15:
1223 ret = GRB_PER;
1224 break; // Mean Period of Combined Wind Waves and Swell
1225 }
1226 break;
1227
1228 case 1: // Currents
1229 switch (dataNum) {
1230 case 0:
1231 ret = GRB_CUR_DIR;
1232 break;
1233 case 1:
1234 ret = GRB_CUR_SPEED;
1235 break;
1236 case 2:
1237 ret = GRB_UOGRD;
1238 break; // DATA_TO_GRBV2[DATA_CURRENT_VX] = grb2DataType(10,1,2);
1239 case 3:
1240 ret = GRB_VOGRD;
1241 break; // DATA_TO_GRBV2[DATA_CURRENT_VY] = grb2DataType(10,1,3);
1242 }
1243 break;
1244 case 3: // Surface Properties
1245 switch (dataNum) {
1246 case 0:
1247 ret = GRB_WTMP;
1248 break; // DATA_TO_GRBV2[DATA_CURRENT_VX] = grb2DataType(10,1,2);
1249 }
1250 break;
1251 }
1252 break;
1253 }
1254#if 1
1255 if (ret == 255) {
1256 erreur("unknown Discipline %d dataCat %d dataNum %d", productDiscipline,
1257 dataCat, dataNum);
1258 }
1259#endif
1260 return ret;
1261}
1262
1264static int mapStatisticalEndTime(GRIBMessage *grid) {
1265 // lovely md.fcst_time is in grid->md.time_unit but
1266 // md.stat_proc.t[0].time_length is in grid->md.stat_proc.t[0].time_unit not
1267 // always the same.
1268 if (grid->md.time_unit == grid->md.stat_proc.t[0].time_unit)
1269 switch (grid->md.time_unit) { // table 4.4
1270 case 0: // minute
1271 // return (grid->md.stat_proc.etime/100 % 100)-(grid->time/100 % 100);
1272 case 1: // hour
1273 return grid->md.fcst_time + grid->md.stat_proc.t[0].time_length;
1274 // return (grid->md.stat_proc.etime/10000- grid->time/10000);
1275 case 2: // Day
1276 return (grid->md.stat_proc.edy - grid->dy);
1277 case 3:
1278 return (grid->md.stat_proc.emo - grid->mo);
1279 case 4:
1280 return (grid->md.stat_proc.eyr - grid->yr);
1281 default:
1282 fprintf(stderr, "Unable to map end time with units %d to GRIB1\n",
1283 grid->md.time_unit);
1284 return UINT_MAX;
1285 }
1286
1287 if (grid->md.time_unit == 0 && grid->md.stat_proc.t[0].time_unit == 1) {
1288 // in minute + hourly increment
1289 return grid->md.fcst_time + grid->md.stat_proc.t[0].time_length * 60;
1290 }
1291
1292 if (grid->md.time_unit == 1 && grid->md.stat_proc.t[0].time_unit == 0 &&
1293 (grid->md.stat_proc.t[0].time_unit % 60) != 0) {
1294 // convert in hour
1295 return grid->md.fcst_time + grid->md.stat_proc.t[0].time_length / 60;
1296 }
1297
1298 fprintf(stderr, "Unable to map end time %d %d %d %d \n", grid->md.time_unit,
1299 grid->md.stat_proc.t[0].time_unit, grid->md.fcst_time,
1300 grid->md.stat_proc.t[0].time_length);
1301 return UINT_MAX;
1302}
1303
1304// map GRIB2 msg time to GRIB1 P1 and P2 in sec
1305static bool mapTimeRange(GRIBMessage *grid, zuint *p1, zuint *p2,
1306 zuchar *t_range, int *n_avg, int *n_missing,
1307 int center) {
1308 switch (grid->md.pds_templ_num) {
1309 case 0:
1310 case 1:
1311 case 2:
1312 case 15:
1313 *t_range = 0;
1314 *p1 = grid->md.fcst_time;
1315 *p2 = 0;
1316 *n_avg = *n_missing = 0;
1317 break;
1318 case 8:
1319 case 11:
1320 case 12:
1321 if (grid->md.stat_proc.num_ranges > 1) {
1322 if (center == 7 && grid->md.stat_proc.num_ranges == 2) {
1323 /* NCEP CFSR monthly grids */
1324 *p2 = grid->md.stat_proc.t[0].incr_length;
1325 *p1 = *p2 - grid->md.stat_proc.t[1].time_length;
1326 *n_avg = grid->md.stat_proc.t[0].time_length;
1327 switch (grid->md.stat_proc.t[0].proc_code) {
1328 case 193:
1329 *t_range = 113;
1330 break;
1331 case 194:
1332 *t_range = 123;
1333 break;
1334 case 195:
1335 *t_range = 128;
1336 break;
1337 case 196:
1338 *t_range = 129;
1339 break;
1340 case 197:
1341 *t_range = 130;
1342 break;
1343 case 198:
1344 *t_range = 131;
1345 break;
1346 case 199:
1347 *t_range = 132;
1348 break;
1349 case 200:
1350 *t_range = 133;
1351 break;
1352 case 201:
1353 *t_range = 134;
1354 break;
1355 case 202:
1356 *t_range = 135;
1357 break;
1358 case 203:
1359 *t_range = 136;
1360 break;
1361 case 204:
1362 *t_range = 137;
1363 break;
1364 case 205:
1365 *t_range = 138;
1366 break;
1367 case 206:
1368 *t_range = 139;
1369 break;
1370 case 207:
1371 *t_range = 140;
1372 break;
1373 default:
1374 fprintf(
1375 stderr,
1376 "Unable to map NCEP statistical process code %d to GRIB1\n",
1377 grid->md.stat_proc.t[0].proc_code);
1378 return false;
1379 }
1380 } else {
1381 fprintf(stderr,
1382 "Unable to map multiple statistical processes to GRIB1\n");
1383 return false;
1384 }
1385 } else {
1386 switch (grid->md.stat_proc.t[0].proc_code) {
1387 case 0:
1388 case 1:
1389 case 4:
1390 switch (grid->md.stat_proc.t[0].proc_code) {
1391 case 0: /* average */
1392 *t_range = 3;
1393 break;
1394 case 1: /* accumulation */
1395 *t_range = 4;
1396 break;
1397 case 4: /* difference */
1398 *t_range = 5;
1399 break;
1400 }
1401 *p1 = grid->md.fcst_time;
1402 *p2 = mapStatisticalEndTime(grid);
1403 if (*p2 == UINT_MAX) {
1404 return false;
1405 }
1406 if (grid->md.stat_proc.t[0].incr_length == 0)
1407 *n_avg = 0;
1408 else {
1409 fprintf(stderr, "Unable to map discrete processing to GRIB1\n");
1410 return false;
1411 }
1412 break;
1413
1414 case 2: // maximum
1415 case 3: // minimum
1416 *t_range = 2;
1417 *p1 = grid->md.fcst_time;
1418 *p2 = mapStatisticalEndTime(grid);
1419 if (*p2 == UINT_MAX) {
1420 return false;
1421 }
1422 if (grid->md.stat_proc.t[0].incr_length == 0)
1423 *n_avg = 0;
1424 else {
1425 fprintf(stderr, "Unable to map discrete processing to GRIB1\n");
1426 return false;
1427 }
1428 break;
1429 default:
1430 // patch for NCEP grids
1431 if (grid->md.stat_proc.t[0].proc_code == 255 && center == 7) {
1432 if (grid->disc == 0) {
1433 if (grid->md.param_cat == 0) {
1434 switch (grid->md.param_num) {
1435 case 4:
1436 case 5:
1437 *t_range = 2;
1438 *p1 = grid->md.fcst_time;
1439 *p2 = mapStatisticalEndTime(grid);
1440 if (*p2 == UINT_MAX) {
1441 return false;
1442 }
1443 if (grid->md.stat_proc.t[0].incr_length == 0)
1444 *n_avg = 0;
1445 else {
1446 fprintf(stderr,
1447 "Unable to map discrete processing to GRIB1\n");
1448 return false;
1449 }
1450 break;
1451 }
1452 }
1453 }
1454 } else {
1455 fprintf(stderr, "Unable to map statistical process %d to GRIB1\n",
1456 grid->md.stat_proc.t[0].proc_code);
1457 return false;
1458 }
1459 }
1460 }
1461 *n_missing = grid->md.stat_proc.nmiss;
1462 break;
1463 default:
1464 fprintf(stderr,
1465 "Unable to map time range for Product Definition Template %d "
1466 "into GRIB1\n",
1467 grid->md.pds_templ_num);
1468 return false;
1469 }
1470 return true;
1471}
1472
1473//-------------------------------------------------------------------------------
1474// Adjust data type from different mete center
1475//-------------------------------------------------------------------------------
1476void GribV2Record::translateDataType() {
1477 this->known_data = true;
1478 data_center_model = OTHER_DATA_CENTER;
1479 //------------------------
1480 // NOAA GFS
1481 //------------------------
1482 if (data_type == GRB_PRECIP_RATE) { // mm/s -> mm/h
1483 multiplyAllData(3600.0);
1484 }
1485 if (id_center == 7 && id_model == 2) // NOAA
1486 {
1487 data_center_model = NOAA_GFS;
1488 // altitude level (entire atmosphere vs entire atmosphere considered as 1
1489 // level)
1490 if (level_type == LV_ATMOS_ENT) {
1491 level_type = LV_ATMOS_ALL;
1492 }
1493 if (data_type == GRB_TEMP // gfs Water surface Temperature
1494 && level_type == LV_GND_SURF && level_value == 0)
1495 data_type = GRB_WTMP;
1496 }
1497 //------------------------
1498 // DNMI-NEurope.grb
1499 //------------------------
1500 else if (id_center == 7 && id_model == 88 && id_grid == 255) { // saildocs
1501 data_center_model = NOAA_NCEP_WW3;
1502 }
1503 //----------------------------
1504 // NOAA RTOFS
1505 //--------------------------------
1506 else if (id_center == 7 && id_model == 45 && id_grid == 255) {
1507 data_center_model = NOAA_RTOFS;
1508 }
1509 //----------------------------------------------
1510 // NCEP sea surface temperature
1511 //----------------------------------------------
1512 else if ((id_center == 7 && id_model == 44 && id_grid == 173) ||
1513 (id_center == 7 && id_model == 44 && id_grid == 235)) {
1514 data_center_model = NOAA_NCEP_SST;
1515 }
1516 //----------------------------------------------
1517 // FNMOC WW3 mediterranean sea
1518 //----------------------------------------------
1519 else if (id_center == 58 && id_model == 111 && id_grid == 179) {
1520 data_center_model = FNMOC_WW3_MED;
1521 }
1522 //----------------------------------------------
1523 // FNMOC WW3
1524 //----------------------------------------------
1525 else if (id_center == 58 && id_model == 110 && id_grid == 240) {
1526 data_center_model = FNMOC_WW3_GLB;
1527 }
1528 //------------------------
1529 // Meteorem (Scannav)
1530 //------------------------
1531 else if (id_center == 59 && id_model == 78 && id_grid == 255) {
1532 // data_center_model = ??
1533 if ((GetDataType() == GRB_WIND_VX || GetDataType() == GRB_WIND_VY) &&
1534 GetLevelType() == LV_MSL && GetLevelValue() == 0) {
1535 level_type = LV_ABOV_GND;
1536 level_value = 10;
1537 }
1538 if (GetDataType() == GRB_PRECIP_TOT && GetLevelType() == LV_MSL &&
1539 GetLevelValue() == 0) {
1540 level_type = LV_GND_SURF;
1541 level_value = 0;
1542 }
1543 } else if (id_center == 84 && id_model <= 5 && id_grid == 0) {
1544 }
1545 // MeteoFrance
1546 else if (id_center == 85) {
1547 if (data_type == GRB_CLOUD_TOT && level_type == LV_GND_SURF &&
1548 level_value == 0) {
1549 level_type = LV_ATMOS_ALL;
1550 }
1551 }
1552
1553 //------------------------
1554 // Unknown center
1555 //------------------------
1556 else {
1557 data_center_model = OTHER_DATA_CENTER;
1558 // printf("Uncorrected GribRecord: ");
1559 // this->print();
1560 // this->known_data = false;
1561 }
1562 // translate significant wave height and dir
1563 if (this->known_data) {
1564 switch (level_type) {
1565 case 100: // LV_ISOBARIC
1566 /* GRIB1 is in hectoPascal
1567 GRIB2 in Pascal, convert to GRIB1
1568 */
1569 level_value = level_value / 100;
1570 break;
1571 case 103:
1572 level_type = LV_ABOV_GND;
1573 break;
1574 case 101:
1575 level_type = LV_MSL;
1576 break;
1577 }
1578 switch (GetDataType()) {
1579 case GRB_WIND_GUST:
1580 level_type = LV_GND_SURF;
1581 level_value = 0;
1582 break;
1583 case GRB_UOGRD:
1584 case GRB_VOGRD:
1585 break;
1586 case GRB_WVHGT:
1587 case GRB_HTSGW:
1588 case GRB_WVDIR:
1589 case GRB_WVPER:
1590 case GRB_DIR:
1591 case GRB_PER:
1592 level_type = LV_GND_SURF;
1593 level_value = 0;
1594 break;
1595 }
1596 }
1597 // this->print();
1598}
1599
1600// -------------------------------------
1601void GribV2Record::readDataSet(ZUFILE *file) {
1602 bool skip = false;
1603 bool DS = false;
1604 int len, sec_num;
1605
1606 data = nullptr;
1607 bms_bits = nullptr;
1608 hasBMS = false;
1609 known_data = false;
1610 is_duplicated = false;
1611
1612 while (strncmp(&((char *)grib_msg->buffer)[grib_msg->offset / 8], "7777",
1613 4) != 0) {
1614 DS = false;
1615 getBits(grib_msg->buffer, &len, grib_msg->offset, 32);
1616 getBits(grib_msg->buffer, &sec_num, grib_msg->offset + 4 * 8, 8);
1617 switch (sec_num) {
1618 case 2: // Section 2: Local Use Section
1619 if (skip == true) break;
1620 ok = unpackLUS(grib_msg);
1621 break;
1622 case 3: // Section 3: Grid Definition Section
1623 if (skip == true) break;
1624 ok = unpackGDS(grib_msg);
1625 if (ok) {
1626 Ni = grib_msg->md.nx;
1627 Nj = grib_msg->md.ny;
1628 La1 = grib_msg->md.slat;
1629 Lo1 = grib_msg->md.slon;
1630 La2 = grib_msg->md.lats.elat;
1631 Lo2 = grib_msg->md.lons.elon;
1632 Di = grib_msg->md.xinc.loinc;
1633 Dj = grib_msg->md.yinc.lainc;
1634 scan_flags = grib_msg->md.scan_mode;
1635 is_scan_i_positive = (scan_flags & 0x80) == 0;
1636 is_scan_j_positive = (scan_flags & 0x40) != 0;
1637 is_adjacent_i = (scan_flags & 0x20) == 0;
1638 if (Lo1 >= 0 && Lo1 <= 180 && Lo2 < 0)
1639 Lo2 +=
1640 360.0; // cross the 180 deg meridien,beetwen alaska and russia
1641
1642 if (is_scan_i_positive)
1643 while (Lo1 > Lo2) { // horizontal size > 360 °
1644 Lo1 -= 360.0;
1645 }
1646 if (Lo2 > Lo1) {
1647 lon_min = Lo1;
1648 lon_max = Lo2;
1649 } else {
1650 lon_min = Lo2;
1651 lon_max = Lo1;
1652 }
1653 if (La2 > La1) {
1654 lat_min = La1;
1655 lat_max = La2;
1656 } else {
1657 lat_min = La2;
1658 lat_max = La1;
1659 }
1660 if (Ni <= 1 || Nj <= 1) {
1661 erreur("Record %d: Ni=%d Nj=%d", id, Ni, Nj);
1662 ok = false;
1663 } else {
1664 Di = (Lo2 - Lo1) / (Ni - 1);
1665 Dj = (La2 - La1) / (Nj - 1);
1666 }
1667 }
1668 break;
1669 case 4: // Section 4: Product Definition Section
1670 if (skip == true) break;
1671 ok = unpackPDS(grib_msg);
1672 if (ok) {
1673 // printf("template %d 0 meteo data cat %d data num %d\n",
1674 // grib_msg->md.pds_templ_num, grib_msg->md.param_cat,
1675 // grib_msg->md.param_num);
1676 productTemplate = grib_msg->md.pds_templ_num;
1677 dataCat = grib_msg->md.param_cat;
1678 dataNum = grib_msg->md.param_num;
1679 data_type = GRBV2_TO_DATA(productDiscipline, dataCat, dataNum);
1680 if (data_type == 255) {
1681 // printf("unused data type, skip\n");
1682 skip = true;
1683 break;
1684 }
1685
1686 level_type = grib_msg->md.lvl1_type;
1687 level_value = grib_msg->md.lvl1;
1688 if (grib_msg->md.lvl2_type == 8 && grib_msg->md.lvl1_type == 1) {
1689 // cf table 4.5: 8 Nominal top of the atmosphere
1690 level_type = LV_ATMOS_ALL;
1691 level_value = 0.;
1692 }
1693 int n_avg, n_missing;
1694
1695 if (!mapTimeRange(grib_msg, &period_p1, &period_p2, &time_range,
1696 &n_avg, &n_missing, id_center)) {
1697 skip = true;
1698 break;
1699 }
1700 periodsec = periodSeconds(grib_msg->md.time_unit, period_p1,
1701 period_p2, time_range);
1702 SetRecordCurrentDate(MakeDate(refyear, refmonth, refday, refhour,
1703 refminute, periodsec));
1704 // printf("%d %d %d %d %d %d \n",
1705 // refyear,refmonth,refday,refhour,refminute,periodsec); printf("%d
1706 // Periode %d P1=%d p2=%d %s\n", grib_msg->md.time_unit, periodsec,
1707 // period_p1,period_p2, str_cur_date);
1708 }
1709 break;
1710 case 5: // Section 5: Data Representation Section
1711 if (skip == true) break;
1712 ok = unpackDRS(grib_msg);
1713 break;
1714 case 6: // Section 6: Bit-Map Section
1715 if (skip == true) break;
1716 ok = unpackBMS(grib_msg);
1717 if (ok) {
1718 if (grib_msg->md.bmssize != 0) {
1719 hasBMS = true;
1720 bms_size = grib_msg->md.bmssize;
1721 bms_bits = new zuchar[grib_msg->md.bmssize];
1722 memcpy(bms_bits, grib_msg->md.bms, grib_msg->md.bmssize);
1723 }
1724 }
1725 break;
1726 case 7: // Section 7: Data Section
1727 if (skip == false) {
1728 ok = unpackDS(grib_msg);
1729 if (ok) {
1730 data = grib_msg->grids.gridpoints;
1731 grib_msg->grids.gridpoints = 0;
1732 }
1733 }
1734 if (grib_msg->num_grids != 1) DS = true;
1735 break;
1736 }
1737 grib_msg->offset += len * 8;
1738 if (ok == false || DS == true) break;
1739 }
1740
1741 // ok = false;
1742 if (false) {
1743 // if (true) {
1744 printf("==== GV2 %d\n", ok);
1745 printf("Lo1=%f Lo2=%f La1=%f La2=%f\n", Lo1, Lo2, La1, La2);
1746 printf("Lo1=%f Lo2=%f La1=%f La2=%f\n", grib_msg->md.slon,
1747 grib_msg->md.lons.elon, grib_msg->md.slat, grib_msg->md.lats.elat);
1748 printf("Ni=%d Nj=%d\n", Ni, Nj);
1749 printf("has_di_dj=%d Di,Dj=(%f %f)\n", has_di_dj, Di, Dj);
1750 printf("is_scan_i_positive=%d is_scan_j_positive=%d is_adjacent_i=%d\n",
1751 is_scan_i_positive, is_scan_j_positive, is_adjacent_i);
1752 printf("hasBMS=%d\n", hasBMS);
1753 }
1754 if (ok) {
1755 if (!skip) {
1756 translateDataType();
1757 SetDataType(data_type);
1758 }
1759 }
1760 if (!ok || !DS ||
1761 strncmp(&((char *)grib_msg->buffer)[grib_msg->offset / 8], "7777", 4) ==
1762 0) {
1763 delete grib_msg;
1764 grib_msg = 0;
1765 }
1766}
1767
1768// -----------------
1769GribV2Record::GribV2Record(ZUFILE *file, int id_) {
1770 id = id_;
1771 seekStart = zu_tell(file); // moved to section 0 read
1772 data = nullptr;
1773 bms_size = 0;
1774 bms_bits = nullptr;
1775 hasBMS = false;
1776 eof = false;
1777 known_data = false;
1778 is_duplicated = false;
1779 long start = seekStart;
1780
1781 grib_msg = new GRIBMessage();
1782
1783 // Pre read 4 bytes to check for length adder needed for some GRIBS (like
1784 // WRAMS and NAM)
1785 char strgrib[5];
1786 if (zu_read(file, strgrib, 4) != 4) {
1787 ok = false;
1788 eof = true;
1789 return;
1790 }
1791
1792 bool b_haveReadGRIB = false; // already read the "GRIB" of section 0 ??
1793
1794 if (strncmp(strgrib, "GRIB", 4) != 0)
1795 b_len_add_8 = true;
1796 else {
1797 b_len_add_8 = false;
1798 b_haveReadGRIB = true;
1799 }
1800
1801 // Another special case, where zero padding is used between records.
1802 if ((strgrib[0] == 0) && (strgrib[1] == 0) && (strgrib[2] == 0) &&
1803 (strgrib[3] == 0)) {
1804 b_len_add_8 = false;
1805 b_haveReadGRIB = false;
1806 }
1807 ok = readGribSection0_IS(file,
1808 b_haveReadGRIB); // Section 0: Indicator Section
1809
1810 int len, sec_num;
1811 if (ok) {
1812 unpackIDS(grib_msg); // Section 1: Identification Section
1813 int off;
1814 /* find out how many grids are in this message */
1815 off = grib_msg->offset / 8;
1816 while (strncmp(&((char *)grib_msg->buffer)[off], "7777", 4) != 0) {
1817 len = uint4(grib_msg->buffer + off);
1818 sec_num = grib_msg->buffer[off + 4];
1819 if (sec_num == 7) grib_msg->num_grids++;
1820 off += len;
1821 }
1822 } else {
1823 // seek back if V1
1824 (void)zu_seek(file, start, SEEK_SET);
1825 return;
1826 }
1827 refyear = grib_msg->yr;
1828 refmonth = grib_msg->mo;
1829 refday = grib_msg->dy;
1830 refhour = grib_msg->time / 10000;
1831 refminute = (grib_msg->time / 100) % 100;
1832 ref_date = MakeDate(refyear, refmonth, refday, refhour, refminute, 0);
1833 sprintf(str_ref_date, "%04d-%02d-%02d %02d:%02d", refyear, refmonth, refday,
1834 refhour, refminute);
1835 id_center = grib_msg->center_id;
1836 id_model = grib_msg->table_ver;
1837 id_grid = 0; // FIXME data1[6];
1838 productDiscipline = grib_msg->disc;
1839 readDataSet(file);
1840}
1841
1842// ---------------------------------------
1843bool GribV2Record::hasMoreDataSet() const {
1844 return grib_msg && grib_msg->num_grids != 1 ? true : false;
1845}
1846
1847// ---------------------------------------
1848GribV2Record *GribV2Record::GribV2NextDataSet(ZUFILE *file, int id_) {
1849 GribV2Record *rec1 = new GribV2Record(*this);
1850 // XXX should have a shallow copy constructor
1851 delete[] rec1->data;
1852 delete[] rec1->bms_bits;
1853 // new records take ownership
1854 this->grib_msg = 0;
1855 rec1->id = id_;
1856 rec1->readDataSet(file);
1857 return rec1;
1858}
1859
1860//-------------------------------------------------------------------------------
1861// Constructeur de recopie
1862//-------------------------------------------------------------------------------
1863#pragma warning(disable : 4717)
1864GribV2Record::GribV2Record(const GribRecord &rec) : GribRecord(rec) {
1865 *this = rec;
1866#pragma warning(default : 4717)
1867}
1868
1869GribV2Record::~GribV2Record() { delete grib_msg; }
1870
1871//==============================================================
1872// Lecture des données
1873//==============================================================
1874//----------------------------------------------
1875// SECTION 0: THE INDICATOR SECTION (IS)
1876//----------------------------------------------
1877static bool unpackIS(ZUFILE *fp, GRIBMessage *grib_msg) {
1878 unsigned char temp[16];
1879 int status;
1880 size_t num;
1881
1882 if (grib_msg->buffer != nullptr) {
1883 delete[] grib_msg->buffer;
1884 grib_msg->buffer = nullptr;
1885 }
1886 grib_msg->num_grids = 0;
1887
1888 if ((status = zu_read(fp, &temp[4], 12)) != 12) {
1889 return false;
1890 }
1891 grib_msg->disc = temp[6];
1892 grib_msg->ed_num = temp[7];
1893
1894 // Bail out early if this is not GRIB2
1895 if (grib_msg->ed_num != 2) return false;
1896
1897 getBits(temp, &grib_msg->total_len, 96, 32);
1898 // too small or overflow
1899 if (grib_msg->total_len < 16 || grib_msg->total_len > (INT_MAX - 4))
1900 return false;
1901
1902 grib_msg->md.nx = grib_msg->md.ny = 0;
1903 grib_msg->buffer = new unsigned char[grib_msg->total_len + 4];
1904 memcpy(grib_msg->buffer, temp, 16);
1905 num = grib_msg->total_len - 16;
1906
1907 status = zu_read(fp, &grib_msg->buffer[16], num);
1908 if (status != (int)num) return false;
1909
1910 if (strncmp(&((char *)grib_msg->buffer)[grib_msg->total_len - 4], "7777",
1911 4) != 0)
1912 fprintf(stderr, "Warning: no end section found\n");
1913
1914 grib_msg->offset = 128;
1915 return true;
1916}
1917
1918bool GribV2Record::readGribSection0_IS(ZUFILE *file, bool b_skip_initial_GRIB) {
1919 char strgrib[4];
1920 fileOffset0 = zu_tell(file);
1921
1922 if (!b_skip_initial_GRIB) {
1923 // Cherche le 1er 'G'
1924 while ((zu_read(file, strgrib, 1) == 1) && (strgrib[0] != 'G')) {
1925 }
1926
1927 if (strgrib[0] != 'G') {
1928 ok = false;
1929 eof = true;
1930 return false;
1931 }
1932 if (zu_read(file, strgrib + 1, 3) != 3) {
1933 ok = false;
1934 eof = true;
1935 return false;
1936 }
1937 if (strncmp(strgrib, "GRIB", 4) != 0) {
1938 printf("readGribSection0_IS(): Unknown file header : %c%c%c%c\n",
1939 strgrib[0], strgrib[1], strgrib[2], strgrib[3]);
1940 ok = false;
1941 eof = true;
1942 return false;
1943 }
1944 }
1945
1946 seekStart = zu_tell(file) - 4;
1947 // totalSize = readInt3(file);
1948 if (unpackIS(file, grib_msg) == false) {
1949 ok = false;
1950 eof = true;
1951 return false;
1952 }
1953
1954 edition_number = grib_msg->ed_num;
1955 if (edition_number != 2) {
1956 ok = false;
1957 eof = true;
1958 return false;
1959 }
1960
1961 return true;
1962}
1963
1964//==============================================================
1965// Fonctions utiles
1966//==============================================================
1967zuint GribV2Record::periodSeconds(zuchar unit, zuint P1, zuint P2,
1968 zuchar range) {
1969 zuint res, dur;
1970
1971 switch (unit) {
1972 case 0: // Minute
1973 res = 60;
1974 break;
1975 case 1: // Hour
1976 res = 3600;
1977 break;
1978 case 2: // Day
1979 res = 86400;
1980 break;
1981 case 10: // 3 hours
1982 res = 10800;
1983 break;
1984 case 11: // 6 hours
1985 res = 21600;
1986 break;
1987 case 12: // 12 hours
1988 res = 43200;
1989 break;
1990 case 13: // Second
1991 res = 1;
1992 break;
1993 case 3: // Month
1994 case 4: // Year
1995 case 5: // Decade (10 years)
1996 case 6: // Normal (30 years)
1997 case 7: // Century (100 years)
1998 default:
1999 erreur("id=%d: unknown time unit in PDS b18=%d", id, unit);
2000 res = 0;
2001 ok = false;
2002 }
2003 grib_debug("id=%d: PDS unit %d (time range) b21=%d %d P1=%d P2=%d\n", id,
2004 unit, range, res, P1, P2);
2005 dur = 0;
2006
2007 switch (range) {
2008 case 0:
2009 dur = (zuint)P1;
2010 break;
2011 case 1:
2012 dur = 0;
2013 break;
2014
2015 case 2:
2016 case 3: // Average (reference time + P1 to reference time + P2)
2017 // dur = ((zuint)P1+(zuint)P2)/2; break; // TODO
2018 dur = (zuint)P2;
2019 break;
2020
2021 case 4: // Accumulation (reference time + P1 to reference time + P2)
2022 dur = (zuint)P2;
2023 break;
2024
2025 case 10:
2026 dur = ((zuint)P1 << 8) + (zuint)P2;
2027 break;
2028 default:
2029 erreur("id=%d: unknown time range in PDS b21=%d", id, range);
2030 dur = 0;
2031 ok = false;
2032 }
2033 return res * dur;
2034}
2035
2036//===============================================================================================
A meteorological data grid from a GRIB (Gridded Binary) file.
bool eof
Signals when the end of the GRIB file has been reached during parsing.
zuint periodsec
Forecast period in seconds.
bool is_duplicated
Indicates if this record was created through copying rather than direct reading.
double Lo2
Grid end coordinates.
zuint period_p1
Time range indicators for this forecast step.
double Lo1
Grid origin coordinates.
zuchar id_model
Model identifier within the originating center.
zuchar GetDataType() const
Returns the type of meteorological parameter stored in this grid.
zuchar id_grid
Grid identifier used by the originating center.
bool ok
Indicates record validity.
int id
Unique identifier for this record.
bool hasBMS
Indicates presence of a bitmap section.
zuint level_value
Numeric value associated with level_type.
zuint GetLevelValue() const
Returns the numeric value associated with the level type.
zuint refyear
Components of the reference time for this forecast.
zuchar data_type
Parameter identifier as defined by GRIB tables.
time_t ref_date
Unix timestamp of model initialization time.
zuchar level_type
Vertical level type indicator.
bool known_data
Indicates whether the data type in this record is recognized by the parser.
int data_center_model
Identifies the numerical weather model that produced this data.
zuchar id_center
Originating center ID as defined by WMO common table C-1.
zuchar edition_number
GRIB edition number, indicating the version of the GRIB specification used.
zuchar time_range
Statistical processing indicator.
zuchar GetLevelType() const
Returns the type of vertical level for this grid's data.
GRIB Version 2 Record Implementation.