Line data Source code
1 : /*****************************************************************************
2 : * degrib2.c
3 : *
4 : * DESCRIPTION
5 : * This file contains the main driver routines to call the unpack grib2
6 : * library functions. It also contains the code needed to figure out the
7 : * dimensions of the arrays before calling the FORTRAN library.
8 : *
9 : * HISTORY
10 : * 9/2002 Arthur Taylor (MDL / RSIS): Created.
11 : * 12/2002 Tim Kempisty, Ana Canizares, Tim Boyer, & Marc Saccucci
12 : * (TK,AC,TB,&MS): Code Review 1.
13 : *
14 : * NOTES
15 : *****************************************************************************
16 : */
17 : #include <stdio.h>
18 : #include <string.h>
19 : #include <stdlib.h>
20 : #include <math.h>
21 :
22 : #include <limits>
23 :
24 : #include "myassert.h"
25 : #include "myerror.h"
26 : #include "tendian.h"
27 : #include "meta.h"
28 : #include "metaname.h"
29 : //#include "write.h"
30 : #include "degrib2.h"
31 : #include "degrib1.h"
32 : #if 0
33 : /* tdlpack is no longer supported by GDAL */
34 : #include "tdlpack.h"
35 : #endif
36 : #include "grib2api.h"
37 : //#include "mymapf.h"
38 : #include "clock.h"
39 :
40 : #define GRIB_UNSIGN_INT3(a,b,c) ((a<<16)+(b<<8)+c)
41 :
42 : /*****************************************************************************
43 : * ReadSect0() -- Review 12/2002
44 : *
45 : * Arthur Taylor / MDL
46 : *
47 : * PURPOSE
48 : * Looks for the next GRIB message, by looking for the keyword "GRIB". It
49 : * expects the message in "expect" bytes from the start, but could find the
50 : * message in "expect2" bytes or 0 bytes from the start. Returns -1 if it
51 : * can't find "GRIB", 1 if "GRIB" is not 0, "expect", or "expect2" bytes from
52 : * the start.
53 : * It stores the bytes it reads (a max of "expect") up to but not including
54 : * the 'G' in "GRIB" in wmo.
55 : *
56 : * After it finds section 0, it then parses the 16 bytes that make up
57 : * section 0 so that it can return the length of the entire GRIB message.
58 : *
59 : * When done, it sets fp to point to the end of Sect0.
60 : *
61 : * The reason for this procedure is so that we can read in the size of the
62 : * grib message, and thus allocate enough memory to read the message in before
63 : * making it Big endian, and passing it to the library for unpacking.
64 : *
65 : * ARGUMENTS
66 : * fp = A pointer to an opened file in which to read.
67 : * When done, this points to the start of section 1. (Input/Output)
68 : * buff = The data between messages. (Input/Output)
69 : * buffLen = The length of buff (Output)
70 : * limit = How many bytes to read before giving up and stating it is not
71 : * a proper message. (-1 means no limit). (Input)
72 : * sect0 = The read in Section 0 (as seen on disk). (Output)
73 : * gribLen = Length of this GRIB message. (Output)
74 : * version = 1 if GRIB1 message, 2 if GRIB2 message, -1 if TDLP message.
75 : * (Output)
76 : * expect = The expected number of bytes to find "GRIB" in. (Input)
77 : * expect2 = The second possible number of bytes to find "GRIB" in. (Input)
78 : * wmo = Assumed allocated to be at least size "expect".
79 : * Holds the bytes before the first "GRIB" message.
80 : * expect should be > expect2, but is up to caller (Output)
81 : * wmoLen = Length of wmo (total number of bytes read - SECT0LEN_WORD * 4).
82 : * (Output)
83 : *
84 : * FILES/DATABASES:
85 : * An already opened "GRIB2" File
86 : *
87 : * RETURNS: int (could use errSprintf())
88 : * 1 = Length of wmo was != 0 and was != expect
89 : * 0 = OK
90 : * -1 = Couldn't find "GRIB" part of message.
91 : * -2 = Ran out of file while reading this section.
92 : * -3 = Grib version was not 1 or 2.
93 : * -4 = Most significant sInt4 of GRIB length was not 0
94 : * -5 = Grib message length was <= 16 (can't be smaller than just sect 0)
95 : *
96 : * HISTORY
97 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
98 : * 11/2002 AAT: Combined with ReadWMOHeader
99 : * 12/2002 (TK,AC,TB,&MS): Code Review.
100 : * 1/2003 AAT: Bug found. wmo access out of bounds of expect when setting
101 : * the /0 element, if wmoLen > expect.
102 : * 4/2003 AAT: Added ability to handle GRIB version 1.
103 : * 5/2003 AAT: Added limit option.
104 : * 8/2003 AAT: Removed dependence on offset, and fileLen.
105 : * 10/2004 AAT: Modified to allow for TDLP files
106 : *
107 : * NOTES
108 : * 1a) 1196575042L == ASCII representation of "GRIB" (GRIB in MSB)
109 : * 1b) 1112101447L == ASCII representation of "BIRG" (GRIB in LSB)
110 : * 1c) 1413762128L == ASCII representation of "TDLP" (TDLP in MSB)
111 : * 1d) 1347175508L == ASCII representation of "PLDT" (TDLP in LSB)
112 : * 2) Takes advantage of the wordType to check that the edition is correct.
113 : * 3) May want to return prodType.
114 : * 4) WMO_HEADER_ORIG_LEN was added for backward compatibility... should be
115 : * removed when we no longer use old format. (say in a year from 11/2002)
116 : *
117 : *****************************************************************************
118 : */
119 1244 : int ReadSECT0 (VSILFILE *fp, char **buff, uInt4 *buffLen, sInt4 limit,
120 : sInt4 sect0[SECT0LEN_WORD], uInt4 *gribLen, int *version)
121 : {
122 : typedef union {
123 : sInt4 li;
124 : unsigned char buffer[4];
125 : } wordType;
126 :
127 1244 : uChar gribMatch = 0; /* Counts how many letters in GRIB we've matched. */
128 : #if 0
129 : /* tdlpack is no longer supported by GDAL */
130 : uChar tdlpMatch = 0; /* Counts how many letters in TDLP we've matched. */
131 : #endif
132 : wordType word; /* Used to check that the edition is correct. */
133 : uInt4 curLen; /* Where we currently are in buff. */
134 : uInt4 i; /* Used to loop over the first few char's */
135 : uInt4 stillNeed; /* Number of bytes still needed to get 1st 8 bytes of
136 : * message into memory. */
137 :
138 : /* Get first 8 bytes. If GRIB we don't care. If TDLP, this is the length
139 : * of record. Read at least 1 record (length + 2 * 8) + 8 (next record
140 : * length) + 8 bytes before giving up. */
141 1244 : curLen = 8;
142 1244 : if (*buffLen < curLen) {
143 1233 : *buffLen = curLen;
144 1233 : *buff = (char *) realloc ((void *) *buff, *buffLen * sizeof (char));
145 : }
146 1244 : if (VSIFReadL(*buff, sizeof (char), curLen, fp) != curLen) {
147 1 : errSprintf ("ERROR: Couldn't find 'GRIB' or 'TDLP'\n");
148 1 : return -1;
149 : }
150 : /*
151 : Can't do the following because we don't know if the file is a GRIB file or
152 : not, or if it was a FORTRAN file.
153 : if (limit > 0) {
154 : MEMCPY_BIG (&recLen, *buff, 4);
155 : limit = (limit > recLen + 32) ? limit : recLen + 32;
156 : }
157 : */
158 3325 : while (
159 : #if 0
160 : /* tdlpack is no longer supported by GDAL */
161 : (tdlpMatch != 4) &&
162 : #endif
163 4568 : (gribMatch != 4)) {
164 5407 : for (i = curLen - 8; i + 7 < curLen; i++) {
165 3325 : if ((*buff)[i] == 'G') {
166 1245 : if (((*buff)[i + 1] == 'R') && ((*buff)[i + 2] == 'I') &&
167 1243 : ((*buff)[i + 3] == 'B')) {
168 1243 : if (((*buff)[i + 7] == 1) ||
169 1102 : ((*buff)[i + 7] == 2)) {
170 1243 : gribMatch = 4;
171 1243 : break;
172 : }
173 : }
174 : }
175 : #if 0
176 : /* tdlpack is no longer supported by GDAL */
177 : else if ((*buff)[i] == 'T') {
178 : if (((*buff)[i + 1] == 'D') && ((*buff)[i + 2] == 'L') &&
179 : ((*buff)[i + 3] == 'P')) {
180 : tdlpMatch = 4;
181 : break;
182 : }
183 : }
184 : #endif
185 : }
186 3325 : stillNeed = i - (curLen - 8);
187 : /* Read enough of message to have the first 8 bytes (including ID). */
188 3325 : if (stillNeed != 0) {
189 2082 : curLen += stillNeed;
190 2082 : if ((limit >= 0) && (curLen > (size_t) limit)) {
191 0 : errSprintf ("ERROR: Couldn't find type in %ld bytes\n", limit);
192 0 : *buffLen = curLen - stillNeed;
193 0 : return -1;
194 : }
195 2082 : if (*buffLen < curLen) {
196 22 : myAssert (200 > stillNeed);
197 22 : *buffLen = *buffLen + 200;
198 : /* *buffLen = curLen; */
199 22 : *buff = (char *) realloc ((void *) *buff,
200 22 : *buffLen * sizeof (char));
201 : }
202 2082 : if (VSIFReadL((*buff) + (curLen - stillNeed), sizeof (char), stillNeed, fp) != stillNeed) {
203 0 : errSprintf ("ERROR: Ran out of file reading SECT0\n");
204 0 : *buffLen = curLen;
205 0 : return -1;
206 : }
207 : }
208 : }
209 : /* Following is needed because we are increasing buffLen at a rate of
210 : * 200 (to save reallocs), so it may not actually line up with the length
211 : * of buffer. curLen should always be the length of buffer. */
212 1243 : *buffLen = curLen;
213 :
214 : /* curLen and (*buff) hold 8 bytes of section 0. */
215 1243 : curLen -= 8;
216 1243 : memcpy (&(sect0[0]), (*buff) + curLen, 4);
217 : #ifdef DEBUG
218 : #ifdef LITTLE_ENDIAN
219 1243 : myAssert ((sect0[0] == 1112101447L) || (sect0[0] == 1347175508L));
220 : #else
221 : myAssert ((sect0[0] == 1196575042L) || (sect0[0] == 1413762128L));
222 : #endif
223 : #endif
224 1243 : memcpy (&(sect0[1]), *buff + curLen + 4, 4);
225 : /* Make sure we don't pass back part of "GRIB" in the buffer. */
226 1243 : (*buff)[curLen] = '\0';
227 1243 : *buffLen = curLen;
228 :
229 1243 : word.li = sect0[1];
230 : #if 0
231 : /* tdlpack is no longer supported by GDAL */
232 : if (tdlpMatch == 4) {
233 : if (word.buffer[3] != 0) {
234 : errSprintf ("ERROR: unexpected version of TDLP in SECT0\n");
235 : return -2;
236 : }
237 : *version = -1;
238 : /* Find out the GRIB Message Length */
239 : *gribLen = GRIB_UNSIGN_INT3 (word.buffer[0], word.buffer[1],
240 : word.buffer[2]);
241 : /* Min message size: GRIB1=52, TDLP=59, GRIB2=86. */
242 : if (*gribLen < 59) {
243 : errSprintf ("TDLP length %ld was < 59?\n", *gribLen);
244 : return -5;
245 : }
246 : } else
247 : #endif
248 1243 : if (word.buffer[3] == 1) {
249 141 : *version = 1;
250 : /* Find out the GRIB Message Length */
251 141 : *gribLen = GRIB_UNSIGN_INT3 (word.buffer[0], word.buffer[1],
252 : word.buffer[2]);
253 : /* Min message size: GRIB1=52, TDLP=59, GRIB2=86. */
254 141 : if (*gribLen < 52) {
255 0 : errSprintf ("GRIB1 length %ld was < 52?\n", *gribLen);
256 0 : return -5;
257 : }
258 1102 : } else if (word.buffer[3] == 2) {
259 1102 : *version = 2;
260 : /* Make sure we still have enough file for the rest of section 0. */
261 1102 : if (VSIFReadL(sect0 + 2, sizeof (sInt4), 2, fp) != 2) {
262 0 : errSprintf ("ERROR: Ran out of file reading SECT0\n");
263 0 : return -2;
264 : }
265 1102 : if (sect0[2] != 0) {
266 0 : errSprintf ("Most significant sInt4 of GRIB length was not 0?\n");
267 0 : errSprintf ("This is either an error, or we have a single GRIB "
268 : "message which is larger than 2^31 = 2,147,283,648 "
269 : "bytes.\n");
270 0 : return -4;
271 : }
272 : #ifdef LITTLE_ENDIAN
273 1102 : revmemcpy (gribLen, &(sect0[3]), sizeof (sInt4));
274 : #else
275 : *gribLen = sect0[3];
276 : #endif
277 : } else {
278 0 : errSprintf ("ERROR: Not TDLPack, and Grib edition is not 1 or 2\n");
279 0 : return -3;
280 : }
281 1243 : return 0;
282 : }
283 :
284 : /*****************************************************************************
285 : * FindGRIBMsg() -- Review 12/2002
286 : *
287 : * Arthur Taylor / MDL
288 : *
289 : * PURPOSE
290 : * Jumps through a GRIB2 file looking for a specific message. Currently
291 : * that message is determined by msgNum which is in the range of 1..n.
292 : * In the future we may be searching based on projection or date.
293 : *
294 : * ARGUMENTS
295 : * fp = The current GRIB2 file to look through. (Input)
296 : * msgNum = Which message to look for. (Input)
297 : * offset = Where in the file the message starts (this is before the
298 : * wmo ASCII part if there is one.) (Output)
299 : * curMsg = The current # of messages we have looked through. (In/Out)
300 : *
301 : * FILES/DATABASES:
302 : * An already opened "GRIB2" File
303 : *
304 : * RETURNS: int (could use errSprintf())
305 : * 0 = OK
306 : * -1 = Problems reading Section 0.
307 : * -2 = Ran out of file.
308 : *
309 : * HISTORY
310 : * 11/2002 Arthur Taylor (MDL/RSIS): Created.
311 : * 12/2002 (TK,AC,TB,&MS): Code Review.
312 : * 6/2003 Matthew T. Kallio (matt@wunderground.com):
313 : * "wmo" dimension increased to WMO_HEADER_LEN + 1 (for '\0' char)
314 : * 8/2003 AAT: Removed dependence on offset and fileLen.
315 : *
316 : * NOTES
317 : *****************************************************************************
318 : */
319 0 : int FindGRIBMsg (VSILFILE *fp, int msgNum, sInt4 *offset, int *curMsg)
320 : {
321 : int cnt; /* The current message we are looking at. */
322 0 : char *buff = nullptr; /* Holds the info between records. */
323 : uInt4 buffLen; /* Length of info between records. */
324 : sInt4 sect0[SECT0LEN_WORD]; /* Holds the current Section 0. */
325 : uInt4 gribLen; /* Length of the current GRIB message. */
326 : int version; /* Which version of GRIB is in this message. */
327 : char c; /* Determine if end of the file without fileLen. */
328 : sInt4 jump; /* How far to jump to get to past GRIB message. */
329 :
330 0 : cnt = *curMsg + 1;
331 0 : buffLen = 0;
332 0 : while (VSIFReadL(&c, sizeof(char), 1, fp) == 1) {
333 0 : VSIFSeekL(fp, VSIFTellL(fp) - sizeof(char), SEEK_SET);
334 :
335 0 : if (cnt >= msgNum) {
336 : /* 12/1/2004 version 1.63 forgot to free buff */
337 0 : free (buff);
338 0 : *curMsg = cnt;
339 0 : return 0;
340 : }
341 : /* Read section 0 to find gribLen and wmoLen. */
342 0 : if (ReadSECT0 (fp, &buff, &buffLen, GRIB_LIMIT, sect0, &gribLen,
343 0 : &version) < 0) {
344 0 : preErrSprintf ("Inside FindGRIBMsg\n");
345 0 : free (buff);
346 0 : return -1;
347 : }
348 0 : myAssert ((version == 1) || (version == 2) || (version == -1));
349 : /* Continue on to the next grib message. */
350 0 : if ((version == 1) || (version == -1)) {
351 0 : jump = gribLen - 8;
352 : } else {
353 0 : jump = gribLen - 16;
354 : }
355 0 : VSIFSeekL(fp, jump, SEEK_CUR);
356 0 : *offset = *offset + gribLen + buffLen;
357 0 : cnt++;
358 : }
359 0 : free (buff);
360 0 : *curMsg = cnt - 1;
361 : /* Return -2 since we reached the end of file. This may not be an error
362 : * (multiple file option). */
363 0 : return -2;
364 : /*
365 : errSprintf ("ERROR: Ran out of file looking for msgNum %d.\n", msgNum);
366 : errSprintf (" Current msgNum %d\n", cnt);
367 : */
368 : }
369 :
370 : /*****************************************************************************
371 : * FindSectLen2to7() --
372 : *
373 : * Arthur Taylor / MDL
374 : *
375 : * PURPOSE
376 : * Looks through a GRIB message and finds out the maximum size of each
377 : * section. Simpler if there is only one grid in the message.
378 : *
379 : * ARGUMENTS
380 : * c_ipack = The current GRIB2 message. (Input)
381 : * gribLen = Length of c_ipack. (Input)
382 : * ns = Array of section lengths. (Output)
383 : * sectNum = Which section to start with. (Input)
384 : * curTot = on going total read from c_ipack. (Input)
385 : * nd2x3 = Total number of grid points (Output)
386 : * table50 = Type of packing used. (See code table 5.0) (GS5_SIMPLE = 0,
387 : * GS5_CMPLX = 2, GS5_CMPLXSEC = 3) (Output)
388 : *
389 : * FILES/DATABASES: None
390 : *
391 : * RETURNS: int (could use errSprintf())
392 : * 0 = OK
393 : * -1 = Ran of data in a section
394 : * -2 = Section not properly labeled.
395 : *
396 : * HISTORY
397 : * 3/2003 AAT: Created
398 : *
399 : * NOTES
400 : * 1) Assumes that the pack method of multiple grids are the same.
401 : *****************************************************************************
402 : */
403 466 : static int FindSectLen2to7 (unsigned char *c_ipack, sInt4 gribLen, sInt4 ns[8],
404 : char sectNum, sInt4 *curTot, sInt4 *nd2x3,
405 : short int *table50)
406 : {
407 : sInt4 sectLen; /* The length of the current section. */
408 : sInt4 li_temp; /* A temporary holder of sInt4s. */
409 :
410 466 : if ((sectNum == 2) || (sectNum == 3)) {
411 : /* Figure out the size of section 2 and 3. */
412 : /* ERO: check change from + 5 to +6+4 per r39022 */
413 457 : if (*curTot > gribLen - (6 + 4)) {
414 0 : errSprintf ("ERROR: Ran out of data in Section 2 or 3\n");
415 0 : return -1;
416 : }
417 : /* Handle optional section 2. */
418 457 : if (c_ipack[*curTot + 4] == 2) {
419 421 : MEMCPY_BIG (§Len, c_ipack + *curTot, 4);
420 421 : if( sectLen < 0 || *curTot > INT_MAX - sectLen ) {
421 0 : errSprintf ("ERROR: Invalid sectLen for section 2\n");
422 0 : return -1;
423 : }
424 421 : *curTot = *curTot + sectLen;
425 421 : if (ns[2] < sectLen)
426 421 : ns[2] = sectLen;
427 : /* ERO: check change from + 5 to +6+4 per r39022 */
428 421 : if (*curTot + 6 + 4 > gribLen) {
429 0 : errSprintf ("ERROR: Ran out of data in Section 3\n");
430 0 : return -1;
431 : }
432 : }
433 : /* Handle section 3. */
434 457 : if (c_ipack[*curTot + 4] != 3) {
435 0 : errSprintf ("ERROR: Section 3 labeled as %d\n",
436 0 : c_ipack[*curTot + 4]);
437 0 : return -2;
438 : }
439 457 : MEMCPY_BIG (§Len, c_ipack + *curTot, 4);
440 457 : if( sectLen < 0 || *curTot > INT_MAX - sectLen ) {
441 0 : errSprintf ("ERROR: Invalid sectLen for section 3\n");
442 0 : return -1;
443 : }
444 457 : if (ns[3] < sectLen)
445 457 : ns[3] = sectLen;
446 : /* While we are here, grab the total number of grid points nd2x3. */
447 457 : MEMCPY_BIG (&li_temp, c_ipack + *curTot + 6, 4);
448 457 : if (*nd2x3 < li_temp)
449 457 : *nd2x3 = li_temp;
450 457 : *curTot = *curTot + sectLen;
451 : }
452 : /*
453 : #ifdef DEBUG
454 : printf ("Section len (2=%ld) (3=%ld)\n", ns[2], ns[3]);
455 : #endif
456 : */
457 :
458 : /* Figure out the size of section 4. */
459 466 : if (*curTot > gribLen - 5) {
460 0 : errSprintf ("ERROR: Ran out of data in Section 4\n");
461 0 : return -1;
462 : }
463 466 : if (c_ipack[*curTot + 4] != 4) {
464 0 : errSprintf ("ERROR: Section 4 labeled as %d\n", c_ipack[*curTot + 4]);
465 0 : return -2;
466 : }
467 466 : MEMCPY_BIG (§Len, c_ipack + *curTot, 4);
468 466 : if( sectLen < 0 || *curTot > INT_MAX - sectLen ) {
469 0 : errSprintf ("ERROR: Invalid sectLen for section 4\n");
470 0 : return -1;
471 : }
472 466 : if (ns[4] < sectLen)
473 457 : ns[4] = sectLen;
474 466 : *curTot = *curTot + sectLen;
475 : /*
476 : #ifdef DEBUG
477 : printf ("Section len (4=%ld < %ld)\n", sectLen, ns[4]);
478 : #endif
479 : */
480 :
481 : /* Figure out the size of section 5. */
482 : /* ERO: check change from + 5 to +9+2 per r39127 */
483 466 : if (*curTot > gribLen - (9 + 2)) {
484 0 : errSprintf ("ERROR: Ran out of data in Section 5\n");
485 0 : return -1;
486 : }
487 466 : if (c_ipack[*curTot + 4] != 5) {
488 0 : errSprintf ("ERROR: Section 5 labeled as %d\n", c_ipack[*curTot + 4]);
489 0 : return -2;
490 : }
491 466 : MEMCPY_BIG (§Len, c_ipack + *curTot, 4);
492 466 : if( sectLen < 0 || *curTot > INT_MAX - sectLen ) {
493 0 : errSprintf ("ERROR: Invalid sectLen for section 5\n");
494 0 : return -1;
495 : }
496 : /* While we are here, grab the packing method. */
497 466 : MEMCPY_BIG (table50, c_ipack + *curTot + 9, 2);
498 466 : if (ns[5] < sectLen)
499 457 : ns[5] = sectLen;
500 466 : *curTot = *curTot + sectLen;
501 : /*
502 : #ifdef DEBUG
503 : printf ("Section len (5=%ld < %ld)\n", sectLen, ns[5]);
504 : #endif
505 : */
506 :
507 : /* Figure out the size of section 6. */
508 466 : if (*curTot > gribLen - 5) {
509 0 : errSprintf ("ERROR: Ran out of data in Section 6\n");
510 0 : return -1;
511 : }
512 466 : if (c_ipack[*curTot + 4] != 6) {
513 0 : errSprintf ("ERROR: Section 6 labeled as %d\n", c_ipack[*curTot + 4]);
514 0 : return -2;
515 : }
516 466 : MEMCPY_BIG (§Len, c_ipack + *curTot, 4);
517 466 : if( sectLen < 0 || *curTot > INT_MAX - sectLen ) {
518 0 : errSprintf ("ERROR: Invalid sectLen for section 6\n");
519 0 : return -1;
520 : }
521 466 : if (ns[6] < sectLen)
522 457 : ns[6] = sectLen;
523 466 : *curTot = *curTot + sectLen;
524 : /*
525 : #ifdef DEBUG
526 : printf ("Section len (6=%ld < %ld)\n", sectLen, ns[6]);
527 : #endif
528 : */
529 :
530 : /* Figure out the size of section 7. */
531 466 : if (*curTot > gribLen - 5) {
532 0 : errSprintf ("ERROR: Ran out of data in Section 7\n");
533 0 : return -1;
534 : }
535 466 : if (c_ipack[*curTot + 4] != 7) {
536 0 : errSprintf ("ERROR: Section 7 labeled as %d\n", c_ipack[*curTot + 4]);
537 0 : return -2;
538 : }
539 466 : MEMCPY_BIG (§Len, c_ipack + *curTot, 4);
540 466 : if( sectLen < 0 || *curTot > INT_MAX - sectLen ) {
541 0 : errSprintf ("ERROR: Invalid sectLen for section 7\n");
542 0 : return -1;
543 : }
544 466 : if (ns[7] < sectLen)
545 457 : ns[7] = sectLen;
546 466 : *curTot = *curTot + sectLen;
547 : /*
548 : #ifdef DEBUG
549 : printf ("Section len (7=%ld < %ld)\n", sectLen, ns[7]);
550 : #endif
551 : */
552 466 : return 0;
553 : }
554 :
555 : /*****************************************************************************
556 : * FindSectLen() -- Review 12/2002
557 : *
558 : * Arthur Taylor / MDL
559 : *
560 : * PURPOSE
561 : * Looks through a GRIB message and finds out how big each section is.
562 : *
563 : * ARGUMENTS
564 : * c_ipack = The current GRIB2 message. (Input)
565 : * gribLen = Length of c_ipack. (Input)
566 : * ns = Array of section lengths. (Output)
567 : * nd2x3 = Total number of grid points (Output)
568 : * table50 = Type of packing used. (See code table 5.0) (GS5_SIMPLE = 0,
569 : * GS5_CMPLX = 2, GS5_CMPLXSEC = 3) (Output)
570 : *
571 : * FILES/DATABASES: None
572 : *
573 : * RETURNS: int (could use errSprintf())
574 : * 0 = OK
575 : * -1 = Ran of data in a section
576 : * -2 = Section not properly labeled.
577 : *
578 : * HISTORY
579 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
580 : * 11/2002 AAT: Updated.
581 : * 12/2002 (TK,AC,TB,&MS): Code Review.
582 : * 3/2003 AAT: Made it handle multiple grids in the same GRIB2 message.
583 : * 5/2003 AAT: Bug: Initialized size of section 2..6 to -1, instead
584 : * of 2..7.
585 : *
586 : * NOTES
587 : * 1) Assumes that the pack method of multiple grids are the same.
588 : *****************************************************************************
589 : */
590 457 : static int FindSectLen (unsigned char *c_ipack, sInt4 gribLen, sInt4 ns[8],
591 : sInt4 *nd2x3, short int *table50)
592 : {
593 : sInt4 curTot; /* Where we are in the current GRIB message. */
594 : char sectNum; /* Which section we are working with. */
595 : int ans; /* The return error code of FindSectLen2to7. */
596 : sInt4 sectLen; /* The length of the current section. */
597 : int i; /* counter as we init ns[]. */
598 :
599 457 : ns[0] = SECT0LEN_WORD * 4;
600 457 : curTot = ns[0];
601 :
602 : /* Figure out the size of section 1. */
603 457 : if (curTot + 5 > gribLen) {
604 0 : errSprintf ("ERROR: Ran out of data in Section 1\n");
605 0 : return -1;
606 : }
607 457 : if (c_ipack[curTot + 4] != 1) {
608 0 : errSprintf ("ERROR: Section 1 labeled as %d\n", c_ipack[curTot + 4]);
609 0 : return -2;
610 : }
611 457 : MEMCPY_BIG (&(ns[1]), c_ipack + curTot, 4);
612 457 : curTot += ns[1];
613 : /*
614 : #ifdef DEBUG
615 : printf ("Section len (0=%ld) (1=%ld)\n", ns[0], ns[1]);
616 : #endif
617 : */
618 457 : sectNum = 2;
619 3199 : for (i = 2; i < 8; i++) {
620 2742 : ns[i] = -1;
621 : }
622 457 : *nd2x3 = -1;
623 9 : do {
624 466 : if ((ans = FindSectLen2to7 (c_ipack, gribLen, ns, sectNum, &curTot,
625 466 : nd2x3, table50)) != 0) {
626 0 : return ans;
627 : }
628 466 : if( curTot + 4 > gribLen ) {
629 0 : errSprintf ("ERROR: Ran out of data in Section 1\n");
630 0 : return -1;
631 : }
632 : /* Try to read section 8. If it is "7777" == 926365495 regardless of
633 : * endian'ness then we have a simple message, otherwise it is complex,
634 : * and we need to read more. */
635 466 : memcpy (§Len, c_ipack + curTot, 4);
636 466 : if (sectLen == 926365495L) {
637 457 : sectNum = 8;
638 : } else {
639 9 : if (curTot + 4 == gribLen) {
640 0 : errSprintf("ERROR: Ran out of data in Section 1\n");
641 0 : return -1;
642 : }
643 9 : sectNum = c_ipack[curTot + 4];
644 9 : if ((sectNum < 2) || (sectNum > 7)) {
645 0 : errSprintf ("ERROR (FindSectLen): Couldn't find the end of the "
646 : "message\n");
647 0 : errSprintf ("and it doesn't appear to repeat sections.\n");
648 0 : errSprintf ("so it is probably an ASCII / binary bug\n");
649 0 : errSprintf ("Max Sect Lengths: %ld %ld %ld %ld %ld %ld %ld"
650 0 : " %ld\n", ns[0], ns[1], ns[2], ns[3], ns[4], ns[5],
651 0 : ns[6], ns[7]);
652 0 : return -2;
653 : }
654 : }
655 466 : } while (sectNum != 8);
656 457 : return 0;
657 : }
658 :
659 : /*****************************************************************************
660 : * IS_Init() -- Review 12/2002
661 : *
662 : * Arthur Taylor / MDL
663 : *
664 : * PURPOSE
665 : * Initialize the IS data structure. The IS_dataType is used to organize
666 : * and allocate all the arrays that the unpack library uses.
667 : * This makes an initial guess for the size of the arrays, and we use
668 : * realloc to increase the size if needed. The write up: "UNPK_GRIB2
669 : * 3/15/02" by Bryon Lawrence, Bob Glahn, David Rudack suggested these numbers
670 : *
671 : * ARGUMENTS
672 : * is = The data structure to initialize. (Output)
673 : *
674 : * FILES/DATABASES: None
675 : *
676 : * RETURNS: void
677 : *
678 : * HISTORY
679 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
680 : * 11/2002 AAT : Updated.
681 : * 12/2002 (TK,AC,TB,&MS): Code Review.
682 : *
683 : * NOTES
684 : * 1) Numbers not found in document were discussed with Bob Glahn on 8/29/2002
685 : * 2) Possible exceptions:
686 : * template 3.120 could need ns[3] = 1600
687 : * template 4.30 could need a different ns4.
688 : * 3) sizeof(float) == sizeof(sInt4), and unpacker does not use both ain
689 : * and iain, so it is possible to have ain and iain point to the same
690 : * memory. Not sure if this is safe, so I haven't done it.
691 : *****************************************************************************
692 : */
693 523 : void IS_Init (IS_dataType *is)
694 : {
695 : int i; /* A simple loop counter. */
696 523 : is->ns[0] = 16;
697 523 : is->ns[1] = 21;
698 523 : is->ns[2] = 7;
699 523 : is->ns[3] = 96;
700 523 : is->ns[4] = 130; /* 60->130 in case there are some S4 time intervals */
701 523 : is->ns[5] = 49;
702 523 : is->ns[6] = 6;
703 523 : is->ns[7] = 8;
704 4707 : for (i = 0; i < 8; i++) {
705 4184 : is->is[i] = (sInt4 *) calloc (is->ns[i], sizeof (sInt4));
706 : }
707 : /* Allocate grid memory. */
708 523 : is->nd2x3 = 0;
709 523 : is->iain = nullptr;
710 523 : is->ib = nullptr;
711 : /* Allocate section 2 int memory. */
712 523 : is->nidat = 0;
713 523 : is->idat = nullptr;
714 : /* Allocate section 2 float memory. */
715 523 : is->nrdat = 0;
716 523 : is->rdat = nullptr;
717 : /* Allocate storage for ipack. */
718 523 : is->ipackLen = 0;
719 523 : is->ipack = nullptr;
720 523 : }
721 :
722 : /*****************************************************************************
723 : * IS_Free() -- Review 12/2002
724 : *
725 : * Arthur Taylor / MDL
726 : *
727 : * PURPOSE
728 : * Free the memory allocated in the IS data structure.
729 : * The IS_dataType is used to organize and allocate all the arrays that the
730 : * unpack library uses.
731 : *
732 : * ARGUMENTS
733 : * is = The data structure to Free. (Output)
734 : *
735 : * FILES/DATABASES: None
736 : *
737 : * RETURNS: void
738 : *
739 : * HISTORY
740 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
741 : * 11/2002 AAT : Updated.
742 : * 12/2002 (TK,AC,TB,&MS): Code Review.
743 : *
744 : * NOTES
745 : *****************************************************************************
746 : */
747 523 : void IS_Free (IS_dataType *is)
748 : {
749 : int i; /* A simple loop counter. */
750 4707 : for (i = 0; i < 8; i++) {
751 4184 : free (is->is[i]);
752 4184 : is->is[i] = nullptr;
753 4184 : is->ns[i] = 0;
754 : }
755 : /* Free grid memory. */
756 523 : free (is->iain);
757 523 : is->iain = nullptr;
758 523 : free (is->ib);
759 523 : is->ib = nullptr;
760 523 : is->nd2x3 = 0;
761 : /* Free section 2 int memory. */
762 523 : free (is->idat);
763 523 : is->idat = nullptr;
764 523 : is->nidat = 0;
765 : /* Free section 2 float memory. */
766 523 : free (is->rdat);
767 523 : is->rdat = nullptr;
768 523 : is->nrdat = 0;
769 : /* Free storage for ipack. */
770 523 : free (is->ipack);
771 523 : is->ipack = nullptr;
772 523 : is->ipackLen = 0;
773 523 : }
774 :
775 : /*****************************************************************************
776 : * ReadGrib2Record() -- Review 12/2002
777 : *
778 : * Arthur Taylor / MDL
779 : *
780 : * PURPOSE
781 : * Reads a GRIB2 message from a file which is already opened and is pointing
782 : * at the correct message. It reads in the message storing the results in
783 : * Grib_Data which is of size grib_DataLen. If needed, it increases
784 : * grib_DataLen enough to fit the current message's grid. It converts (if
785 : * appropriate) the data in Grib_Data to the units specified in f_unit.
786 : *
787 : * In addition it updates offset, and stores the meta data returned by the
788 : * unpacker library in both IS, and (after parsing it) in meta.
789 : *
790 : * Note: It expects meta and IS to already be initialized through calls to
791 : * MetaInit(&meta) and IS_Init(&is) respectively.
792 : *
793 : * ARGUMENTS
794 : * fp = An opened GRIB2 file already at the correct message. (Input)
795 : * fileLen = Length of the opened file. (Input)
796 : * f_unit = 0 use GRIB2 units, 1 use English, 2 use metric. (Input)
797 : * Grib_Data = The read in GRIB2 grid. (Output)
798 : * grib_DataLen = Size of Grib_Data. (Output)
799 : * meta = A filled in meta structure (Output)
800 : * IS = The structure containing all the arrays that the
801 : * unpacker uses (Output)
802 : * subgNum = Which subgrid in the GRIB2 message is of interest.
803 : * (0 = first grid), if it can't find message subgNum,
804 : * returns -5, and an error message (Input)
805 : * majEarth = Used to override the GRIB major axis of earth. (Input)
806 : * minEarth = Used to override the GRIB minor axis of earth. (Input)
807 : * simpVer = The version of the simple weather code to use when parsing
808 : * the WxString. (Input)
809 : * f_endMsg = 1 means we finished reading the previous GRIB message, or
810 : * there was no previous GRIB message. 0 means that we need
811 : * to read a subgrid of the previous message. (Input/Output)
812 : * lwlt, uprt = If the lat is not -100, then lwlt, and uprt define a
813 : * subgrid that the user is interested in. Get the map
814 : * projection out of the GRIB2 message, and do everything
815 : * on the subgrid. (if lwlt, and uprt are not "correct", the
816 : * lat/lons may get swapped) (Input/Output)
817 : *
818 : * FILES/DATABASES:
819 : * An already opened "GRIB2" File
820 : *
821 : * RETURNS: int (could use errSprintf())
822 : * 0 = OK
823 : * -1 = Problems in section 0
824 : * -2 = Problems figuring out the Section Lengths.
825 : * -3 = Error returned by unpack library.
826 : * -4 = Problems parsing the Meta Data.
827 : *
828 : * HISTORY
829 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
830 : * 11/2002 AAT: Updated.
831 : * 12/2002 (TK,AC,TB,&MS): Code Review.
832 : * 1/2003 AAT: It was not error coded 208, but rather 202 to look for.
833 : * 3/2003 AAT: Modified handling of section 2 stuff (no loop)
834 : * 3/2003 AAT: Added ability to handle multiple grids in same message.
835 : * 4/2003 AAT: Added ability to call GRIB1 decoder for GRIB1 messages.
836 : * 5/2003 AAT: Update the offset for ReadGrib1.
837 : * 6/2003 Matthew T. Kallio (matt@wunderground.com):
838 : * "wmo" dimension increased to WMO_HEADER_LEN + 1 (for '\0' char)
839 : * 7/2003 AAT: switched to checking against element name for Wx instead
840 : * of pds2.sect2.ptrType == GS2_WXTYPE
841 : * 7/2003 AAT: Allowed user to override the radius of earth.
842 : * 8/2003 AAT: Removed dependence on fileLen and offset.
843 : * 2/2004 AAT: Added "f_endMsg" logic.
844 : * 2/2004 AAT: Added subgrid potential.
845 : * 2/2004 AAT: Added maj/min Earth override.
846 : *
847 : * NOTES
848 : * 1) Reason ns[7] is not MAX (IS.ns[], local_ns[]) is because local_ns[7]
849 : * is size of the packed message, but ns[7] refers to the returned meta
850 : * data which unpacker library found in section 7, which is a lot smaller.
851 : * 2) Problem: MDL's sect2 is packed and we have no idea how large it is
852 : * when unpacked. So we allocate room for 4000 sInt4s and 500 floats.
853 : * We then check 'jer' for error "202", if we find it we double the size
854 : * and call the unpacker again.
855 : * 3/26/2003: Changed this to be: try once with size
856 : * = max (32 * packed size, 4000)
857 : * Should be fewer calls (more memory intensive) same result, since we had
858 : * been doubling it 5 times.
859 : * 3) For Complex second order packing (GS5_CMPLXSEC) the unpacker needs nd5
860 : * (which is size of message) to be >= nd2x3 (size of grid).
861 : * 3a) Appears to also need this if simple packing, and has a bitmap.
862 : * 4) inew = 1: Currently we only expect 1 grid in 1 GRIB message, although
863 : * the library does allow for multiple grids in a GRIB message.
864 : * 5) iclean = 1: This only maters if there is bitmap data, otherwise it is
865 : * ignored. For bitmap data, if == 0, it embeds the given values for
866 : * xmissp, and xmisss. We don't embed because we don't know what to set
867 : * xmissp or xmisss to. Instead after we know the range, we choose a value
868 : * and walk through the bitmap setting grib_Data appropriately.
869 : * 5a) iclean = 0; This is because we do want the missing values embedded.
870 : * that is we want the missing values to be place holders.
871 : * 6) f_endMsg is true if in the past we either completed reading a message,
872 : * or we haven't read any messages. In either case we need to read the
873 : * next message from file. If f_endMsg is false, then there is more to read
874 : * from IS->ipack, so we don't want to throw it out, nor have to re-read
875 : * ipack from disk.
876 : *
877 : * Question: Should we double ns[2] when we double nrdat, and nidat?
878 : *****************************************************************************
879 : */
880 : #define SECT2_INIT_SIZE 4000
881 : #define UNPK_NUM_ERRORS 22
882 523 : int ReadGrib2Record (VSILFILE *fp, sChar f_unit, double **Grib_Data,
883 : uInt4 *grib_DataLen, grib_MetaData *meta,
884 : IS_dataType *IS, int subgNum, double majEarth,
885 : double minEarth, int simpVer, int simpWWA,
886 : sInt4 *f_endMsg,
887 : CPL_UNUSED LatLon *lwlf,
888 : CPL_UNUSED LatLon *uprt)
889 : {
890 : sInt4 l3264b; /* Number of bits in a sInt4. Needed by FORTRAN
891 : * unpack library to determine if system has a 4
892 : * byte_ sInt4 or an 8 byte sInt4. */
893 523 : char *buff = nullptr; /* Holds the info between records. */
894 : uInt4 buffLen; /* Length of info between records. */
895 : sInt4 sect0[SECT0LEN_WORD]; /* Holds the current Section 0. */
896 : uInt4 gribLen; /* Length of the current GRIB message. */
897 : sInt4 nd5; /* Size of grib message rounded up to the nearest
898 : * sInt4. */
899 : /* A char ptr to the message stored in IS->ipack */
900 523 : unsigned char *c_ipack = nullptr;
901 : sInt4 local_ns[8]; /* Local copy of section lengths. */
902 : sInt4 nd2x3; /* Total number of grid points. */
903 : short int table50; /* Type of packing used. (See code table 5.0)
904 : * (GS5_SIMPLE==0, GS5_CMPLX==2, GS5_CMPLXSEC==3) */
905 : sInt4 nidat; /* Size of section 2 if it contains integer data. */
906 : sInt4 nrdat; /* Size of section 2 if it contains float data. */
907 : sInt4 inew; /* 1 if this is the first grid we are reading. 0 if
908 : * this is the second or later grid from the same
909 : * GRIB message. */
910 523 : sInt4 iclean = 0; /* 0 embed the missing values, 1 don't. */
911 : int j; /* Counter used to find the desired subgrid. */
912 523 : sInt4 kfildo = 5; /* FORTRAN Unit number for diagnostic info. Ignored,
913 : * unless library is compiled a particular way. */
914 523 : sInt4 ibitmap = 0; /* 0 means no bitmap returned, otherwise 1. */
915 523 : float xmissp = 0.0f; /* The primary missing value. If iclean = 0, this
916 : * value is embedded in grid, otherwise it is the
917 : * value returned from the GRIB message. */
918 523 : float xmisss = 0.0f; /* The secondary missing value. If iclean = 0, this
919 : * value is embedded in grid, otherwise it is the
920 : * value returned from the GRIB message. */
921 : sInt4 jer[UNPK_NUM_ERRORS * 2]; /* Any Error codes along with their *
922 : * severity levels generated using the *
923 : * unpack GRIB2 library. */
924 523 : sInt4 ndjer = UNPK_NUM_ERRORS; /* The number of rows in JER( ). */
925 : sInt4 kjer; /* The actual number of errors returned in JER. */
926 : size_t i; /* counter as we loop through jer. */
927 : double unitM, unitB; /* values in y = m x + b used for unit conversion. */
928 : char unitName[15]; /* Holds the string name of the current unit. */
929 : int unitLen; /* String length of string name of current unit. */
930 : int version; /* Which version of GRIB is in this message. */
931 : sInt4 cnt; /* Used to help compact the weather table. */
932 : //gdsType newGds; /* The GDS of the subgrid if needed. */
933 : int x1, y1; /* The original grid coordinates of the lower left
934 : * corner of the subgrid. */
935 : int x2, y2; /* The original grid coordinates of the upper right
936 : * corner of the subgrid. */
937 : uChar f_subGrid; /* True if we have a subgrid. */
938 : sInt4 Nx, Ny; /* original size of the data. */
939 :
940 : /*
941 : * f_endMsg is 1 if in the past we either completed reading a message,
942 : * or we haven't read any messages. In either case we need to read the
943 : * next message from file.
944 : * If f_endMsg is false, then there is more to read from IS->ipack, so we
945 : * don't want to throw it out, nor have to re-read ipack from disk.
946 : */
947 523 : l3264b = sizeof (sInt4) * 8;
948 523 : buffLen = 0;
949 523 : if (*f_endMsg == 1) {
950 523 : if (ReadSECT0 (fp, &buff, &buffLen, -1, sect0, &gribLen, &version) < 0) {
951 0 : preErrSprintf ("Inside ReadGrib2Record\n");
952 0 : free (buff);
953 0 : return -1;
954 : }
955 523 : meta->GribVersion = version;
956 523 : if (version == 1) {
957 66 : if (ReadGrib1Record (fp, f_unit, Grib_Data, grib_DataLen, meta, IS,
958 66 : sect0, gribLen, majEarth, minEarth) != 0) {
959 0 : preErrSprintf ("Problems with ReadGrib1Record called by "
960 : "ReadGrib2Record\n");
961 0 : free (buff);
962 0 : return -1;
963 : }
964 66 : *f_endMsg = 1;
965 66 : free (buff);
966 66 : return 0;
967 : }
968 : #if 0
969 : /* tdlpack is no longer supported by GDAL */
970 : else if (version == -1) {
971 : if (ReadTDLPRecord (fp, Grib_Data, grib_DataLen, meta, IS,
972 : sect0, gribLen, majEarth, minEarth) != 0) {
973 : preErrSprintf ("Problems with ReadGrib1Record called by "
974 : "ReadGrib2Record\n");
975 : free (buff);
976 : return -1;
977 : }
978 : free (buff);
979 : return 0;
980 : }
981 : #endif
982 :
983 : /*
984 : * Make room for entire message, and read it in.
985 : */
986 : /* nd5 needs to be gribLen in (sInt4) units rounded up. */
987 457 : if( gribLen > UINT_MAX - 3 )
988 : {
989 0 : errSprintf("Invalid value of gribLen");
990 0 : free (buff);
991 0 : return -1;
992 : }
993 457 : nd5 = (gribLen + 3) / 4;
994 457 : if (nd5 > IS->ipackLen) {
995 457 : if( gribLen > 100 * 1024 * 1024 )
996 : {
997 0 : vsi_l_offset curPos = VSIFTellL(fp);
998 0 : VSIFSeekL(fp, 0, SEEK_END);
999 0 : vsi_l_offset fileSize = VSIFTellL(fp);
1000 0 : VSIFSeekL(fp, curPos, SEEK_SET);
1001 0 : if( fileSize < gribLen )
1002 : {
1003 0 : errSprintf("File too short");
1004 0 : free (buff);
1005 0 : return -1;
1006 : }
1007 : }
1008 457 : sInt4* ipackNew = (sInt4 *) realloc ((void *) (IS->ipack),
1009 457 : nd5 * sizeof (sInt4));
1010 457 : if( ipackNew == nullptr )
1011 : {
1012 0 : errSprintf("Out of memory");
1013 0 : free (buff);
1014 0 : return -1;
1015 : }
1016 457 : IS->ipackLen = nd5;
1017 457 : IS->ipack = ipackNew;
1018 : }
1019 457 : c_ipack = (unsigned char *) IS->ipack;
1020 : /* Init last sInt4 to 0, to make sure that the padded bytes are 0. */
1021 457 : IS->ipack[nd5 - 1] = 0;
1022 : /* Init first 4 sInt4 to sect0. */
1023 457 : memcpy (c_ipack, sect0, SECT0LEN_WORD * 4);
1024 : /* Read in the rest of the message. */
1025 914 : if (VSIFReadL (c_ipack + SECT0LEN_WORD * 4, sizeof (char),
1026 457 : (gribLen - SECT0LEN_WORD * 4), fp) != (gribLen - SECT0LEN_WORD * 4)) {
1027 0 : errSprintf ("GribLen = %ld, SECT0Len_WORD = %d\n", gribLen,
1028 : SECT0LEN_WORD);
1029 0 : errSprintf ("Ran out of file\n");
1030 0 : free (buff);
1031 0 : return -1;
1032 : }
1033 :
1034 : /*
1035 : * Make sure the arrays are large enough for call to unpacker library.
1036 : */
1037 : /* FindSectLen Does not want (ipack / c_ipack) word swapped, because
1038 : * that would make it much more confusing to find bytes in c_ipack. */
1039 457 : if (FindSectLen (c_ipack, gribLen, local_ns, &nd2x3, &table50) < 0) {
1040 0 : preErrSprintf ("Inside ReadGrib2Record.. Calling FindSectLen\n");
1041 0 : free (buff);
1042 0 : return -2;
1043 : }
1044 457 : if( nd2x3 < 0 || nd2x3 > INT_MAX / static_cast<int>(sizeof (sInt4)) )
1045 : {
1046 0 : preErrSprintf ("Invalid nd2x3\n");
1047 0 : free (buff);
1048 0 : return -2;
1049 : }
1050 :
1051 : /* Make sure all 'is' arrays except ns[7] are MAX (IS.ns[] ,
1052 : * local_ns[]). See note 1 for reason to exclude ns[7] from MAX (). */
1053 3656 : for (i = 0; i < 7; i++) {
1054 3199 : if (local_ns[i] > IS->ns[i]) {
1055 10 : IS->ns[i] = local_ns[i];
1056 10 : IS->is[i] = (sInt4 *) realloc ((void *) (IS->is[i]),
1057 10 : IS->ns[i] * sizeof (sInt4));
1058 : }
1059 : }
1060 :
1061 : /* Allocate room for sect 2. If local_ns[2] = -1 there is no sect 2. */
1062 457 : if (local_ns[2] == -1) {
1063 36 : nidat = 10;
1064 36 : nrdat = 10;
1065 : } else {
1066 : /*
1067 : * See note 2) We have a section 2, so use:
1068 : * MAX (32 * local_ns[2],SECT2_INTSIZE)
1069 : * and MAX (32 * local_ns[2],SECT2_FLOATSIZE)
1070 : * for size of section 2 unpacked.
1071 : */
1072 421 : nidat = (32 * local_ns[2] < SECT2_INIT_SIZE) ? SECT2_INIT_SIZE :
1073 : 32 * local_ns[2];
1074 421 : nrdat = nidat;
1075 : }
1076 457 : if (nidat > IS->nidat) {
1077 457 : IS->idat = (sInt4 *) realloc ((void *) IS->idat,
1078 457 : nidat * sizeof (sInt4));
1079 : // Initialization needed to avoid use of uninitialized memory in
1080 : // ParseSect2_Unknown() on dataset of https://github.com/OSGeo/gdal/issues/5290
1081 457 : if( IS->nidat == 0 )
1082 457 : IS->idat[0] = 0;
1083 457 : IS->nidat = nidat;
1084 : }
1085 457 : if (nrdat > IS->nrdat) {
1086 457 : IS->rdat = (float *) realloc ((void *) IS->rdat,
1087 457 : nrdat * sizeof (float));
1088 : // Initialization needed to avoid use of uninitialized memory in
1089 : // ParseSect2_Unknown() on dataset of https://github.com/OSGeo/gdal/issues/5290
1090 457 : if( IS->nrdat == 0 )
1091 457 : IS->rdat[0] = 0;
1092 457 : IS->nrdat = nrdat;
1093 : }
1094 : /* Make sure we have room for the GRID part of the output. */
1095 457 : if (nd2x3 > IS->nd2x3) {
1096 457 : if( nd2x3 > 100 * 1024 * 1024 )
1097 : {
1098 :
1099 0 : vsi_l_offset curPos = VSIFTellL(fp);
1100 0 : VSIFSeekL(fp, 0, SEEK_END);
1101 0 : vsi_l_offset fileSize = VSIFTellL(fp);
1102 0 : VSIFSeekL(fp, curPos, SEEK_SET);
1103 : // allow a compression ratio of 1:1000
1104 0 : if( (vsi_l_offset)(nd2x3 / 1000) > fileSize )
1105 : {
1106 0 : preErrSprintf ("File too short\n");
1107 0 : free (buff);
1108 0 : return -2;
1109 : }
1110 : }
1111 :
1112 457 : IS->nd2x3 = nd2x3;
1113 457 : if( Grib_Data )
1114 : {
1115 157 : IS->iain = (sInt4 *) realloc ((void *) IS->iain,
1116 157 : IS->nd2x3 * sizeof (sInt4));
1117 : }
1118 457 : IS->ib = (sInt4 *) realloc ((void *) IS->ib,
1119 457 : IS->nd2x3 * sizeof (sInt4));
1120 : }
1121 : /* See note 3) If table50 == 3, unpacker library needs nd5 >= nd2x3. */
1122 457 : if ((table50 == 3) || (table50 == 0)) {
1123 179 : if (nd5 < nd2x3) {
1124 158 : nd5 = nd2x3;
1125 158 : if (nd5 > IS->ipackLen) {
1126 158 : sInt4* ipackNew = (sInt4 *) realloc ((void *) (IS->ipack),
1127 158 : nd5 * sizeof (sInt4));
1128 158 : if( ipackNew == nullptr )
1129 : {
1130 0 : errSprintf("Out of memory");
1131 0 : free (buff);
1132 0 : return -1;
1133 : }
1134 : // zero initialize to avoid later use of undefined values
1135 : // Not sure if it is strictly needed (perhaps some later
1136 : // steps should detect errors / data shortening), but
1137 : // cannot hurt.
1138 : // see https://trac.osgeo.org/gdal/ticket/6967
1139 158 : memset(ipackNew + IS->ipackLen, 0,
1140 158 : (nd5 - IS->ipackLen) * sizeof(sInt4));
1141 158 : IS->ipackLen = nd5;
1142 158 : IS->ipack = ipackNew;
1143 : }
1144 : /* Don't need to do the following, but we do in case code
1145 : * changes. */
1146 158 : c_ipack = (unsigned char *) IS->ipack;
1147 : }
1148 : }
1149 457 : IS->nd5 = nd5;
1150 : /* Unpacker library requires ipack to be MSB. */
1151 : /*
1152 : #ifdef DEBUG
1153 : if (1==1) {
1154 : FILE *fp = fopen ("test.bin", "wb");
1155 : fwrite (IS->ipack, sizeof (sInt4), IS->nd5, fp);
1156 : fclose (fp);
1157 : }
1158 : #endif
1159 : */
1160 : /*
1161 : #ifdef LITTLE_ENDIAN
1162 : memswp (IS->ipack, sizeof (sInt4), IS->nd5);
1163 : #endif
1164 : */
1165 : } else {
1166 0 : c_ipack = (unsigned char *) IS->ipack;
1167 : /* GRIB2 files are in big endian so c_ipack is as well. */
1168 : #ifdef LITTLE_ENDIAN
1169 0 : revmemcpy (&gribLen, &(c_ipack[12]), sizeof (sInt4));
1170 : #else
1171 : memcpy (&gribLen, &(c_ipack[12]), sizeof (sInt4));
1172 : #endif
1173 : }
1174 457 : free (buff);
1175 :
1176 : /* Loop through the grib message looking for the subgNum grid. subgNum
1177 : * goes from 0 to n-1. */
1178 917 : for (j = 0; j <= subgNum; j++) {
1179 460 : if (j == 0) {
1180 457 : inew = 1;
1181 : } else {
1182 3 : inew = 0;
1183 : }
1184 :
1185 : /* Note we are getting data back either as a float or an int, but not
1186 : * both, so we don't need to allocated room for both. */
1187 460 : unpk_g2ncep (&kfildo,
1188 : j == subgNum ? (float *) (IS->iain) : nullptr,
1189 : j == subgNum ? IS->iain : nullptr,
1190 : &(IS->nd2x3),
1191 : IS->idat, &(IS->nidat), IS->rdat, &(IS->nrdat), IS->is[0],
1192 : &(IS->ns[0]), IS->is[1], &(IS->ns[1]), IS->is[2],
1193 : &(IS->ns[2]), IS->is[3], &(IS->ns[3]), IS->is[4],
1194 : &(IS->ns[4]), IS->is[5], &(IS->ns[5]), IS->is[6],
1195 : &(IS->ns[6]), IS->is[7], &(IS->ns[7]), IS->ib, &ibitmap,
1196 : c_ipack, &(IS->nd5), &xmissp, &xmisss, &inew, &iclean,
1197 : &l3264b, f_endMsg, jer, &ndjer, &kjer);
1198 : /*
1199 : unpk_grib2 (&kfildo, (float *) (IS->iain), IS->iain, &(IS->nd2x3),
1200 : IS->idat, &(IS->nidat), IS->rdat, &(IS->nrdat), IS->is[0],
1201 : &(IS->ns[0]), IS->is[1], &(IS->ns[1]), IS->is[2],
1202 : &(IS->ns[2]), IS->is[3], &(IS->ns[3]), IS->is[4],
1203 : &(IS->ns[4]), IS->is[5], &(IS->ns[5]), IS->is[6],
1204 : &(IS->ns[6]), IS->is[7], &(IS->ns[7]), IS->ib, &ibitmap,
1205 : IS->ipack, &(IS->nd5), &xmissp, &xmisss, &inew, &iclean,
1206 : &l3264b, f_endMsg, jer, &ndjer, &kjer);
1207 : */
1208 : /*
1209 : * Check for error messages...
1210 : * If we get an error message, print it, and return.
1211 : */
1212 4140 : for (i = 0; i < (uInt4) kjer; i++) {
1213 3680 : if (jer[ndjer + i] == 0) {
1214 : /* no error. */
1215 0 : } else if (jer[ndjer + i] == 1) {
1216 : /* Warning. */
1217 : #ifdef DEBUG
1218 0 : printf ("Warning: Unpack library warning code (%d %d)\n",
1219 0 : jer[i], jer[ndjer + i]);
1220 : #endif
1221 : } else {
1222 : /* BAD Error. */
1223 0 : errSprintf ("ERROR: Unpack library error code (%ld %ld)\n",
1224 0 : jer[i], jer[ndjer + i]);
1225 0 : return -3;
1226 : }
1227 : }
1228 : }
1229 :
1230 : /* Parse the meta data out. */
1231 457 : if (MetaParse (meta, IS->is[0], IS->ns[0], IS->is[1], IS->ns[1],
1232 : IS->is[2], IS->ns[2], IS->rdat, IS->nrdat, IS->idat,
1233 : IS->nidat, IS->is[3], IS->ns[3], IS->is[4], IS->ns[4],
1234 : IS->is[5], IS->ns[5], gribLen, xmissp, xmisss, simpVer, simpWWA)
1235 457 : != 0) {
1236 : #ifdef DEBUG
1237 : FILE *l_fp;
1238 0 : if ((l_fp = fopen ("dump.is0", "wt")) != nullptr) {
1239 0 : for (i = 0; i < 8; i++) {
1240 0 : fprintf (l_fp, "---Section %d---\n", (int) i);
1241 0 : for (j = 1; j <= IS->ns[i]; j++) {
1242 0 : fprintf (l_fp, "IS%d Item %d = %d\n", (int) i, (int) j, IS->is[i][j - 1]);
1243 : }
1244 : }
1245 0 : fclose (l_fp);
1246 : }
1247 : #endif
1248 0 : preErrSprintf ("Inside ReadGrib2Record.. Problems in MetaParse\n");
1249 0 : return -4;
1250 : }
1251 :
1252 457 : if ((majEarth > 6000) && (majEarth < 7000)) {
1253 0 : if ((minEarth > 6000) && (minEarth < 7000)) {
1254 0 : meta->gds.f_sphere = 0;
1255 0 : meta->gds.majEarth = majEarth;
1256 0 : meta->gds.minEarth = minEarth;
1257 : } else {
1258 0 : meta->gds.f_sphere = 1;
1259 0 : meta->gds.majEarth = majEarth;
1260 0 : meta->gds.minEarth = majEarth;
1261 : }
1262 : }
1263 :
1264 : /* Figure out an equation to pass to ParseGrid to convert the units for
1265 : * this grid. */
1266 : /*
1267 : if (ComputeUnit (meta->pds2.prodType, meta->pds2.sect4.templat,
1268 : meta->pds2.sect4.cat, meta->pds2.sect4.subcat, f_unit,
1269 : &unitM, &unitB, unitName) == 0) {
1270 : */
1271 457 : if (ComputeUnit (meta->convert, meta->unitName, f_unit, &unitM, &unitB,
1272 457 : unitName) == 0) {
1273 61 : unitLen = static_cast<int>(strlen (unitName));
1274 61 : meta->unitName = (char *) realloc ((void *) (meta->unitName),
1275 61 : 1 + unitLen * sizeof (char));
1276 61 : memcpy (meta->unitName, unitName, unitLen);
1277 61 : meta->unitName[unitLen] = '\0';
1278 : }
1279 :
1280 : /* compute the subgrid. */
1281 : /*
1282 : if ((lwlf->lat != -100) && (uprt->lat != -100)) {
1283 : Nx = meta->gds.Nx;
1284 : Ny = meta->gds.Ny;
1285 : if (computeSubGrid (lwlf, &x1, &y1, uprt, &x2, &y2, &(meta->gds),
1286 : &newGds) != 0) {
1287 : preErrSprintf ("ERROR: In compute subgrid.\n");
1288 : return 1;
1289 : }
1290 : // I couldn't decide if I should "permanently" change the GDS or not.
1291 : // when I wrote computeSubGrid. If next line stays, really should
1292 : // rewrite computeSubGrid.
1293 : memcpy (&(meta->gds), &newGds, sizeof (gdsType));
1294 : f_subGrid = 1;
1295 : } else {
1296 : Nx = meta->gds.Nx;
1297 : Ny = meta->gds.Ny;
1298 : x1 = 1;
1299 : x2 = Nx;
1300 : y1 = 1;
1301 : y2 = Ny;
1302 : f_subGrid = 0;
1303 : }
1304 : */
1305 457 : if( meta->gds.Nx == 0 || meta->gds.Nx > INT_MAX ||
1306 457 : meta->gds.Ny == 0 || meta->gds.Ny > INT_MAX )
1307 : {
1308 0 : errSprintf ("Invalid grid dimension.\n");
1309 0 : return -3;
1310 : }
1311 457 : Nx = meta->gds.Nx;
1312 457 : Ny = meta->gds.Ny;
1313 457 : x1 = 1;
1314 457 : x2 = Nx;
1315 457 : y1 = 1;
1316 457 : y2 = Ny;
1317 457 : f_subGrid = 0;
1318 :
1319 : #ifdef deadcode
1320 : /* Figure out if we need iain or ain, and set it to Grib_Data. At the
1321 : * same time handle any bitmaps, and compute some statistics. */
1322 : if ((f_subGrid) && (meta->gds.scan != 64)) {
1323 : errSprintf ("Can not do a subgrid of non scanmode 64 grid yet.\n");
1324 : return -3;
1325 : }
1326 : #endif
1327 :
1328 457 : if (Grib_Data != nullptr && strcmp (meta->element, "Wx") != 0) {
1329 157 : if (strcmp (meta->element, "WWA") != 0) {
1330 157 : ParseGrid (fp, &(meta->gridAttrib), Grib_Data, grib_DataLen, Nx, Ny,
1331 157 : meta->gds.scan, IS->nd2x3, IS->iain, ibitmap, IS->ib, unitM, unitB, 0,
1332 : 0, nullptr, f_subGrid, x1, y1, x2, y2);
1333 : } else {
1334 0 : ParseGrid (fp, &(meta->gridAttrib), Grib_Data, grib_DataLen, Nx, Ny,
1335 0 : meta->gds.scan, IS->nd2x3, IS->iain, ibitmap, IS->ib, unitM, unitB, 1,
1336 : meta->pds2.sect2.hazard.dataLen, meta->pds2.sect2.hazard.f_valid, f_subGrid, x1, y1,
1337 : x2, y2);
1338 : /* compact the table to only those which are actually used. */
1339 0 : cnt = 0;
1340 0 : for (i = 0; i < meta->pds2.sect2.hazard.dataLen; i++) {
1341 0 : if (meta->pds2.sect2.hazard.f_valid[i] == 2) {
1342 0 : meta->pds2.sect2.hazard.haz[i].validIndex = cnt;
1343 0 : cnt++;
1344 0 : } else if (meta->pds2.sect2.hazard.f_valid[i] == 3) {
1345 0 : meta->pds2.sect2.hazard.f_valid[i] = 0;
1346 0 : meta->pds2.sect2.hazard.haz[i].validIndex = cnt;
1347 0 : cnt++;
1348 : } else {
1349 0 : meta->pds2.sect2.hazard.haz[i].validIndex = -1;
1350 : }
1351 : }
1352 : }
1353 300 : } else if( Grib_Data != nullptr ) {
1354 : /* Handle weather grid. ParseGrid looks up the values... If they are
1355 : * "<Invalid>" it sets it to missing (or creates one). If the table
1356 : * entry is used it sets f_valid to 2. */
1357 0 : ParseGrid (fp, &(meta->gridAttrib), Grib_Data, grib_DataLen, Nx, Ny,
1358 0 : meta->gds.scan, IS->nd2x3, IS->iain, ibitmap, IS->ib, unitM, unitB, 1,
1359 : meta->pds2.sect2.wx.dataLen, meta->pds2.sect2.wx.f_valid, f_subGrid, x1, y1,
1360 : x2, y2);
1361 0 : if( *Grib_Data == nullptr )
1362 0 : return -1;
1363 :
1364 : /* compact the table to only those which are actually used. */
1365 0 : cnt = 0;
1366 0 : for (i = 0; i < meta->pds2.sect2.wx.dataLen; i++) {
1367 0 : if (meta->pds2.sect2.wx.f_valid[i] == 2) {
1368 0 : meta->pds2.sect2.wx.ugly[i].validIndex = cnt;
1369 0 : cnt++;
1370 0 : } else if (meta->pds2.sect2.wx.f_valid[i] == 3) {
1371 0 : meta->pds2.sect2.wx.f_valid[i] = 0;
1372 0 : meta->pds2.sect2.wx.ugly[i].validIndex = cnt;
1373 0 : cnt++;
1374 : } else {
1375 0 : meta->pds2.sect2.wx.ugly[i].validIndex = -1;
1376 : }
1377 : }
1378 : } else {
1379 : // Simulate part of ParseGrid() "Resolve bitmap (if there is one) in the data"
1380 : // behavior just to set nodata value.
1381 300 : if (ibitmap && (meta->gridAttrib.f_miss != 1) && (meta->gridAttrib.f_miss != 2)) {
1382 6 : meta->gridAttrib.f_miss = 1;
1383 6 : meta->gridAttrib.missPri = 9999;
1384 : }
1385 : }
1386 :
1387 : /* Figure out some other non-section oriented meta data. */
1388 : /* strftime (meta->refTime, 20, "%Y%m%d%H%M",
1389 : gmtime (&(meta->pds2.refTime)));
1390 : */
1391 457 : Clock_Print (meta->refTime, 20, meta->pds2.refTime, "%Y%m%d%H%M", 0);
1392 : /*
1393 : strftime (meta->validTime, 20, "%Y%m%d%H%M",
1394 : gmtime (&(meta->pds2.sect4.validTime)));
1395 : */
1396 457 : Clock_Print (meta->validTime, 20, meta->pds2.sect4.validTime,
1397 : "%Y%m%d%H%M", 0);
1398 :
1399 457 : const double deltTime = meta->pds2.sect4.validTime - meta->pds2.refTime;
1400 914 : if (deltTime >= std::numeric_limits<sInt4>::max() ||
1401 457 : deltTime <= std::numeric_limits<sInt4>::min()) {
1402 0 : meta->deltTime = 0;
1403 0 : preErrSprintf ("deltTime over range\n");
1404 0 : return -4;
1405 : }
1406 457 : meta->deltTime = static_cast<sInt4>(deltTime);
1407 :
1408 457 : return 0;
1409 : }
1410 :
1411 : #if 0 // unused by GDAL
1412 : int ReadGrib2RecordFast (FILE *fp, sChar f_unit, double **Grib_Data,
1413 : uInt4 *grib_DataLen, grib_MetaData *meta,
1414 : IS_dataType *IS, int subgNum, double majEarth,
1415 : double minEarth, int simpVer, int simpWWA,
1416 : sInt4 *f_endMsg, LatLon *lwlf, LatLon *uprt)
1417 : {
1418 : sInt4 l3264b; /* Number of bits in a sInt4. Needed by FORTRAN
1419 : * unpack library to determine if system has a 4
1420 : * byte_ sInt4 or an 8 byte sInt4. */
1421 : char *buff; /* Holds the info between records. */
1422 : uInt4 buffLen; /* Length of info between records. */
1423 : sInt4 sect0[SECT0LEN_WORD]; /* Holds the current Section 0. */
1424 : uInt4 gribLen; /* Length of the current GRIB message. */
1425 : sInt4 nd5; /* Size of grib message rounded up to the nearest
1426 : * sInt4. */
1427 : unsigned char *c_ipack; /* A char ptr to the message stored in IS->ipack */
1428 : sInt4 local_ns[8]; /* Local copy of section lengths. */
1429 : sInt4 nd2x3; /* Total number of grid points. */
1430 : short int table50; /* Type of packing used. (See code table 5.0)
1431 : * (GS5_SIMPLE==0, GS5_CMPLX==2, GS5_CMPLXSEC==3) */
1432 : sInt4 nidat; /* Size of section 2 if it contains integer data. */
1433 : sInt4 nrdat; /* Size of section 2 if it contains float data. */
1434 : sInt4 inew; /* 1 if this is the first grid we are reading. 0 if
1435 : * this is the second or later grid from the same
1436 : * GRIB message. */
1437 : sInt4 iclean = 0; /* 0 embed the missing values, 1 don't. */
1438 : int j; /* Counter used to find the desired subgrid. */
1439 : sInt4 kfildo = 5; /* FORTRAN Unit number for diagnostic info. Ignored,
1440 : * unless library is compiled a particular way. */
1441 : sInt4 ibitmap; /* 0 means no bitmap returned, otherwise 1. */
1442 : float xmissp; /* The primary missing value. If iclean = 0, this
1443 : * value is embedded in grid, otherwise it is the
1444 : * value returned from the GRIB message. */
1445 : float xmisss; /* The secondary missing value. If iclean = 0, this
1446 : * value is embedded in grid, otherwise it is the
1447 : * value returned from the GRIB message. */
1448 : sInt4 jer[UNPK_NUM_ERRORS * 2]; /* Any Error codes along with their *
1449 : * severity levels generated using the *
1450 : * unpack GRIB2 library. */
1451 : sInt4 ndjer = UNPK_NUM_ERRORS; /* The number of rows in JER( ). */
1452 : sInt4 kjer; /* The actual number of errors returned in JER. */
1453 : size_t i; /* counter as we loop through jer. */
1454 : double unitM, unitB; /* values in y = m x + b used for unit conversion. */
1455 : char unitName[15]; /* Holds the string name of the current unit. */
1456 : int unitLen; /* String length of string name of current unit. */
1457 : int version; /* Which version of GRIB is in this message. */
1458 : gdsType newGds; /* The GDS of the subgrid if needed. */
1459 : int x1, y1; /* The original grid coordinates of the lower left
1460 : * corner of the subgrid. */
1461 : int x2, y2; /* The original grid coordinates of the upper right
1462 : * corner of the subgrid. */
1463 : uChar f_subGrid; /* True if we have a subgrid. */
1464 : sInt4 Nx, Ny; /* original size of the data. */
1465 :
1466 : /*
1467 : * f_endMsg is 1 if in the past we either completed reading a message,
1468 : * or we haven't read any messages. In either case we need to read the
1469 : * next message from file.
1470 : * If f_endMsg is false, then there is more to read from IS->ipack, so we
1471 : * don't want to throw it out, nor have to re-read ipack from disk.
1472 : */
1473 : l3264b = sizeof (sInt4) * 8;
1474 : buff = NULL;
1475 : buffLen = 0;
1476 : if (*f_endMsg == 1) {
1477 : if (ReadSECT0 (fp, &buff, &buffLen, -1, sect0, &gribLen, &version) < 0) {
1478 : preErrSprintf ("Inside ReadGrib2Record\n");
1479 : free (buff);
1480 : return -1;
1481 : }
1482 : meta->GribVersion = version;
1483 : if (version != 2) {
1484 : printf ("Fast parsing doesn't handle this version because ReadGrib1Record/ReadTDLPRecord used Grib_Data[]\n");
1485 : return -1;
1486 : }
1487 :
1488 : /*
1489 : * Make room for entire message, and read it in.
1490 : */
1491 : /* nd5 needs to be gribLen in (sInt4) units rounded up. */
1492 : nd5 = (gribLen + 3) / 4;
1493 : if (nd5 > IS->ipackLen) {
1494 : IS->ipackLen = nd5;
1495 : IS->ipack = (sInt4 *) realloc ((void *) (IS->ipack),
1496 : (IS->ipackLen) * sizeof (sInt4));
1497 : }
1498 : c_ipack = (unsigned char *) IS->ipack;
1499 : /* Init last sInt4 to 0, to make sure that the padded bytes are 0. */
1500 : IS->ipack[nd5 - 1] = 0;
1501 : /* Init first 4 sInt4 to sect0. */
1502 : memcpy (c_ipack, sect0, SECT0LEN_WORD * 4);
1503 : /* Read in the rest of the message. */
1504 : if (fread (c_ipack + SECT0LEN_WORD * 4, sizeof (char),
1505 : (gribLen - SECT0LEN_WORD * 4),
1506 : fp) != (gribLen - SECT0LEN_WORD * 4)) {
1507 : errSprintf ("GribLen = %ld, SECT0Len_WORD = %d\n", gribLen,
1508 : SECT0LEN_WORD);
1509 : errSprintf ("Ran out of file\n");
1510 : free (buff);
1511 : return -1;
1512 : }
1513 :
1514 : /*
1515 : * Make sure the arrays are large enough for call to unpacker library.
1516 : */
1517 : /* FindSectLen Does not want (ipack / c_ipack) word swapped, because
1518 : * that would make it much more confusing to find bytes in c_ipack. */
1519 : if (FindSectLen (c_ipack, gribLen, local_ns, &nd2x3, &table50) < 0) {
1520 : preErrSprintf ("Inside ReadGrib2Record.. Calling FindSectLen\n");
1521 : free (buff);
1522 : return -2;
1523 : }
1524 :
1525 : /* Make sure all 'is' arrays except ns[7] are MAX (IS.ns[] ,
1526 : * local_ns[]). See note 1 for reason to exclude ns[7] from MAX (). */
1527 : for (i = 0; i < 7; i++) {
1528 : if (local_ns[i] > IS->ns[i]) {
1529 : IS->ns[i] = local_ns[i];
1530 : IS->is[i] = (sInt4 *) realloc ((void *) (IS->is[i]),
1531 : IS->ns[i] * sizeof (sInt4));
1532 : }
1533 : }
1534 :
1535 : /* Allocate room for sect 2. If local_ns[2] = -1 there is no sect 2. */
1536 : if (local_ns[2] == -1) {
1537 : nidat = 10;
1538 : nrdat = 10;
1539 : } else {
1540 : /*
1541 : * See note 2) We have a section 2, so use:
1542 : * MAX (32 * local_ns[2],SECT2_INTSIZE)
1543 : * and MAX (32 * local_ns[2],SECT2_FLOATSIZE)
1544 : * for size of section 2 unpacked.
1545 : */
1546 : nidat = (32 * local_ns[2] < SECT2_INIT_SIZE) ? SECT2_INIT_SIZE :
1547 : 32 * local_ns[2];
1548 : nrdat = nidat;
1549 : }
1550 : if (nidat > IS->nidat) {
1551 : IS->nidat = nidat;
1552 : IS->idat = (sInt4 *) realloc ((void *) IS->idat,
1553 : IS->nidat * sizeof (sInt4));
1554 : }
1555 : if (nrdat > IS->nrdat) {
1556 : IS->nrdat = nrdat;
1557 : IS->rdat = (float *) realloc ((void *) IS->rdat,
1558 : IS->nrdat * sizeof (float));
1559 : }
1560 : /* Make sure we have room for the GRID part of the output. */
1561 : if (nd2x3 > IS->nd2x3) {
1562 : IS->nd2x3 = nd2x3;
1563 : IS->iain = (sInt4 *) realloc ((void *) IS->iain,
1564 : IS->nd2x3 * sizeof (sInt4));
1565 : IS->ib = (sInt4 *) realloc ((void *) IS->ib,
1566 : IS->nd2x3 * sizeof (sInt4));
1567 : }
1568 : /* See note 3) If table50 == 3, unpacker library needs nd5 >= nd2x3. */
1569 : if ((table50 == 3) || (table50 == 0)) {
1570 : if (nd5 < nd2x3) {
1571 : nd5 = nd2x3;
1572 : if (nd5 > IS->ipackLen) {
1573 : IS->ipackLen = nd5;
1574 : IS->ipack = (sInt4 *) realloc ((void *) (IS->ipack),
1575 : IS->ipackLen * sizeof (sInt4));
1576 : }
1577 : /* Don't need to do the following, but we do in case code
1578 : * changes. */
1579 : c_ipack = (unsigned char *) IS->ipack;
1580 : }
1581 : }
1582 : IS->nd5 = nd5;
1583 : /* Unpacker library requires ipack to be MSB. */
1584 : /*
1585 : #ifdef DEBUG
1586 : if (1==1) {
1587 : FILE *fp = fopen ("test.bin", "wb");
1588 : fwrite (IS->ipack, sizeof (sInt4), IS->nd5, fp);
1589 : fclose (fp);
1590 : }
1591 : #endif
1592 : */
1593 : } else {
1594 : c_ipack = (unsigned char *) IS->ipack;
1595 : /* GRIB2 files are in big endian so c_ipack is as well. */
1596 : #ifdef LITTLE_ENDIAN
1597 : revmemcpy (&gribLen, &(c_ipack[12]), sizeof (sInt4));
1598 : #else
1599 : memcpy (&gribLen, &(c_ipack[12]), sizeof (sInt4));
1600 : #endif
1601 : }
1602 : free (buff);
1603 :
1604 : /* Loop through the grib message looking for the subgNum grid. subgNum
1605 : * goes from 0 to n-1. */
1606 : for (j = 0; j <= subgNum; j++) {
1607 : if (j == 0) {
1608 : inew = 1;
1609 : } else {
1610 : inew = 0;
1611 : }
1612 :
1613 : /* Note we are getting data back either as a float or an int, but not
1614 : * both, so we don't need to allocated room for both. */
1615 : /*
1616 : unpk_grib2 (&kfildo, (float *) (IS->iain), IS->iain, &(IS->nd2x3),
1617 : IS->idat, &(IS->nidat), IS->rdat, &(IS->nrdat), IS->is[0],
1618 : &(IS->ns[0]), IS->is[1], &(IS->ns[1]), IS->is[2],
1619 : &(IS->ns[2]), IS->is[3], &(IS->ns[3]), IS->is[4],
1620 : &(IS->ns[4]), IS->is[5], &(IS->ns[5]), IS->is[6],
1621 : &(IS->ns[6]), IS->is[7], &(IS->ns[7]), IS->ib, &ibitmap,
1622 : IS->ipack, &(IS->nd5), &xmissp, &xmisss, &inew, &iclean,
1623 : &l3264b, f_endMsg, jer, &ndjer, &kjer);
1624 : */
1625 : c_ipack = (unsigned char *)IS->ipack;
1626 : unpk_g2ncep(&kfildo, (float *) (IS->iain), IS->iain, &(IS->nd2x3),
1627 : IS->idat, &(IS->nidat), IS->rdat, &(IS->nrdat), IS->is[0],
1628 : &(IS->ns[0]), IS->is[1], &(IS->ns[1]), IS->is[2],
1629 : &(IS->ns[2]), IS->is[3], &(IS->ns[3]), IS->is[4],
1630 : &(IS->ns[4]), IS->is[5], &(IS->ns[5]), IS->is[6],
1631 : &(IS->ns[6]), IS->is[7], &(IS->ns[7]), IS->ib, &ibitmap,
1632 : c_ipack, &(IS->nd5), &xmissp, &xmisss, &inew, &iclean,
1633 : &l3264b, f_endMsg, jer, &ndjer, &kjer);
1634 :
1635 :
1636 : /*
1637 : * Check for error messages...
1638 : * If we get an error message, print it, and return.
1639 : */
1640 : for (i = 0; i < (uInt4) kjer; i++) {
1641 : if (jer[ndjer + i] == 0) {
1642 : /* no error. */
1643 : } else if (jer[ndjer + i] == 1) {
1644 : /* Warning. */
1645 : #ifdef DEBUG
1646 : printf ("Warning: Unpack library warning code (%ld %ld)\n",
1647 : jer[i], jer[ndjer + i]);
1648 : #endif
1649 : } else {
1650 : /* BAD Error. */
1651 : errSprintf ("ERROR: Unpack library error code (%ld %ld)\n",
1652 : jer[i], jer[ndjer + i]);
1653 : return -3;
1654 : }
1655 : }
1656 : }
1657 :
1658 : /* Parse the meta data out. */
1659 : if (MetaParse (meta, IS->is[0], IS->ns[0], IS->is[1], IS->ns[1],
1660 : IS->is[2], IS->ns[2], IS->rdat, IS->nrdat, IS->idat,
1661 : IS->nidat, IS->is[3], IS->ns[3], IS->is[4], IS->ns[4],
1662 : IS->is[5], IS->ns[5], gribLen, xmissp, xmisss, simpVer, simpWWA)
1663 : != 0) {
1664 : #ifdef DEBUG
1665 : FILE *fp;
1666 : if ((fp = fopen ("dump.is0", "wt")) != NULL) {
1667 : for (i = 0; i < 8; i++) {
1668 : fprintf (fp, "---Section %d---\n", i);
1669 : for (j = 1; j <= IS->ns[i]; j++) {
1670 : fprintf (fp, "IS%d Item %d = %ld\n", i, j, IS->is[i][j - 1]);
1671 : }
1672 : }
1673 : fclose (fp);
1674 : }
1675 : #endif
1676 : preErrSprintf ("Inside ReadGrib2Record.. Problems in MetaParse\n");
1677 : return -4;
1678 : }
1679 :
1680 : if ((majEarth > 6000) && (majEarth < 7000)) {
1681 : if ((minEarth > 6000) && (minEarth < 7000)) {
1682 : meta->gds.f_sphere = 0;
1683 : meta->gds.majEarth = majEarth;
1684 : meta->gds.minEarth = minEarth;
1685 : } else {
1686 : meta->gds.f_sphere = 1;
1687 : meta->gds.majEarth = majEarth;
1688 : meta->gds.minEarth = majEarth;
1689 : }
1690 : }
1691 :
1692 : /* Figure out an equation to pass to ParseGrid to convert the units for
1693 : * this grid. */
1694 : /*
1695 : if (ComputeUnit (meta->pds2.prodType, meta->pds2.sect4.templat,
1696 : meta->pds2.sect4.cat, meta->pds2.sect4.subcat, f_unit,
1697 : &unitM, &unitB, unitName) == 0) {
1698 : */
1699 : if (ComputeUnit (meta->convert, meta->unitName, f_unit, &unitM, &unitB,
1700 : unitName) == 0) {
1701 : unitLen = strlen (unitName);
1702 : meta->unitName = (char *) realloc ((void *) (meta->unitName),
1703 : 1 + unitLen * sizeof (char));
1704 : strncpy (meta->unitName, unitName, unitLen);
1705 : meta->unitName[unitLen] = '\0';
1706 : }
1707 :
1708 : /* compute the subgrid. */
1709 : if ((lwlf->lat != -100) && (uprt->lat != -100)) {
1710 : Nx = meta->gds.Nx;
1711 : Ny = meta->gds.Ny;
1712 : if (computeSubGrid (lwlf, &x1, &y1, uprt, &x2, &y2, &(meta->gds),
1713 : &newGds) != 0) {
1714 : preErrSprintf ("ERROR: In compute subgrid.\n");
1715 : return 1;
1716 : }
1717 : /* I couldn't decide if I should "permanently" change the GDS or not.
1718 : * when I wrote computeSubGrid. If next line stays, really should
1719 : * rewrite computeSubGrid. */
1720 : memcpy (&(meta->gds), &newGds, sizeof (gdsType));
1721 : f_subGrid = 1;
1722 : } else {
1723 : Nx = meta->gds.Nx;
1724 : Ny = meta->gds.Ny;
1725 : x1 = 1;
1726 : x2 = Nx;
1727 : y1 = 1;
1728 : y2 = Ny;
1729 : f_subGrid = 0;
1730 : }
1731 :
1732 : if ((f_subGrid) && (meta->gds.scan != 64)) {
1733 : errSprintf ("Can not do a subgrid of non scanmode 64 grid yet.\n");
1734 : return -3;
1735 : }
1736 :
1737 : /* Figure out some other non-section oriented meta data. */
1738 : /* strftime (meta->refTime, 20, "%Y%m%d%H%M",
1739 : gmtime (&(meta->pds2.refTime)));
1740 : */
1741 : Clock_Print (meta->refTime, 20, meta->pds2.refTime, "%Y%m%d%H%M", 0);
1742 : /*
1743 : strftime (meta->validTime, 20, "%Y%m%d%H%M",
1744 : gmtime (&(meta->pds2.sect4.validTime)));
1745 : */
1746 : Clock_Print (meta->validTime, 20, meta->pds2.sect4.validTime,
1747 : "%Y%m%d%H%M", 0);
1748 :
1749 : meta->deltTime = (sInt4) (meta->pds2.sect4.validTime - meta->pds2.refTime);
1750 :
1751 : return 0;
1752 : }
1753 : #endif
|