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 #include "myassert.h"
22 #include "myerror.h"
23 #include "memendian.h"
24 #include "meta.h"
25 #include "metaname.h"
26 //#include "write.h"
27 #include "degrib2.h"
28 #include "degrib1.h"
29 #include "tdlpack.h"
30 #include "grib2api.h"
31 //#include "mymapf.h"
32 #include "clock.h"
33
34 #define GRIB_UNSIGN_INT3(a,b,c) ((a<<16)+(b<<8)+c)
35
36 /*****************************************************************************
37 * ReadSect0() -- Review 12/2002
38 *
39 * Arthur Taylor / MDL
40 *
41 * PURPOSE
42 * Looks for the next GRIB message, by looking for the keyword "GRIB". It
43 * expects the message in "expect" bytes from the start, but could find the
44 * message in "expect2" bytes or 0 bytes from the start. Returns -1 if it
45 * can't find "GRIB", 1 if "GRIB" is not 0, "expect", or "expect2" bytes from
46 * the start.
47 * It stores the bytes it reads (a max of "expect") upto but not including
48 * the 'G' in "GRIB" in wmo.
49 *
50 * After it finds section 0, it then parses the 16 bytes that make up
51 * section 0 so that it can return the length of the entire GRIB message.
52 *
53 * When done, it sets fp to point to the end of Sect0.
54 *
55 * The reason for this procedure is so that we can read in the size of the
56 * grib message, and thus allocate enough memory to read the message in before
57 * making it Big endian, and passing it to the library for unpacking.
58 *
59 * ARGUMENTS
60 * fp = A pointer to an opened file in which to read.
61 * When done, this points to the start of section 1. (Input/Output)
62 * buff = The data between messages. (Input/Output)
63 * buffLen = The length of buff (Output)
64 * limit = How many bytes to read before giving up and stating it is not
65 * a proper message. (-1 means no limit). (Input)
66 * sect0 = The read in Section 0 (as seen on disk). (Output)
67 * gribLen = Length of this GRIB message. (Output)
68 * version = 1 if GRIB1 message, 2 if GRIB2 message, -1 if TDLP message.
69 * (Output)
70 * expect = The expected number of bytes to find "GRIB" in. (Input)
71 * expect2 = The second possible number of bytes to find "GRIB" in. (Input)
72 * wmo = Assumed allocated to be at least size "expect".
73 * Holds the bytes before the first "GRIB" message.
74 * expect should be > expect2, but is up to caller (Output)
75 * wmoLen = Length of wmo (total number of bytes read - SECT0LEN_WORD * 4).
76 * (Output)
77 *
78 * FILES/DATABASES:
79 * An already opened "GRIB2" File
80 *
81 * RETURNS: int (could use errSprintf())
82 * 1 = Length of wmo was != 0 and was != expect
83 * 0 = OK
84 * -1 = Couldn't find "GRIB" part of message.
85 * -2 = Ran out of file while reading this section.
86 * -3 = Grib version was not 1 or 2.
87 * -4 = Most significant sInt4 of GRIB length was not 0
88 * -5 = Grib message length was <= 16 (can't be smaller than just sect 0)
89 *
90 * HISTORY
91 * 9/2002 Arthur Taylor (MDL/RSIS): Created.
92 * 11/2002 AAT: Combined with ReadWMOHeader
93 * 12/2002 (TK,AC,TB,&MS): Code Review.
94 * 1/2003 AAT: Bug found. wmo access out of bounds of expect when setting
95 * the /0 element, if wmoLen > expect.
96 * 4/2003 AAT: Added ability to handle GRIB version 1.
97 * 5/2003 AAT: Added limit option.
98 * 8/2003 AAT: Removed dependence on offset, and fileLen.
99 * 10/2004 AAT: Modified to allow for TDLP files
100 *
101 * NOTES
102 * 1a) 1196575042L == ASCII representation of "GRIB" (GRIB in MSB)
103 * 1b) 1112101447L == ASCII representation of "BIRG" (GRIB in LSB)
104 * 1c) 1413762128L == ASCII representation of "TDLP" (TDLP in MSB)
105 * 1d) 1347175508L == ASCII representation of "PLDT" (TDLP in LSB)
106 * 2) Takes advantage of the wordType to check that the edition is correct.
107 * 3) May want to return prodType.
108 * 4) WMO_HEADER_ORIG_LEN was added for backward compatibility... should be
109 * removed when we no longer use old format. (say in a year from 11/2002)
110 *
111 *****************************************************************************
112 */
ReadSECT0(DataSource & fp,char ** buff,uInt4 * buffLen,sInt4 limit,sInt4 sect0[SECT0LEN_WORD],uInt4 * gribLen,int * version)113 int ReadSECT0 (DataSource &fp, char **buff, uInt4 *buffLen, sInt4 limit,
114 sInt4 sect0[SECT0LEN_WORD], uInt4 *gribLen, int *version)
115 {
116 typedef union {
117 sInt4 li;
118 unsigned char buffer[4];
119 } wordType;
120
121 uChar gribMatch = 0; /* Counts how many letters in GRIB we've matched. */
122 uChar tdlpMatch = 0; /* Counts how many letters in TDLP we've matched. */
123 wordType word; /* Used to check that the edition is correct. */
124 uInt4 curLen; /* Where we currently are in buff. */
125 uInt4 i; /* Used to loop over the first few char's */
126 uInt4 stillNeed; /* Number of bytes still needed to get 1st 8 bytes of
127 * message into memory. */
128
129 /* Get first 8 bytes. If GRIB we don't care. If TDLP, this is the length
130 * of record. Read at least 1 record (length + 2 * 8) + 8 (next record
131 * length) + 8 bytes before giving up. */
132 curLen = 8;
133 if (*buffLen < curLen) {
134 *buffLen = curLen;
135 *buff = (char *) realloc ((void *) *buff, *buffLen * sizeof (char));
136 }
137 if (fp.DataSourceFread(*buff, sizeof (char), curLen) != curLen) {
138 errSprintf ("ERROR: Couldn't find 'GRIB' or 'TDLP'\n");
139 return -1;
140 }
141 /*
142 Can't do the following because we don't know if the file is a GRIB file or
143 not, or if it was a FORTRAN file.
144 if (limit > 0) {
145 MEMCPY_BIG (&recLen, *buff, 4);
146 limit = (limit > recLen + 32) ? limit : recLen + 32;
147 }
148 */
149 while ((tdlpMatch != 4) && (gribMatch != 4)) {
150 for (i = curLen - 8; i + 3 < curLen; i++) {
151 if ((*buff)[i] == 'G') {
152 if (((*buff)[i + 1] == 'R') && ((*buff)[i + 2] == 'I') &&
153 ((*buff)[i + 3] == 'B')) {
154 gribMatch = 4;
155 break;
156 }
157 } else if ((*buff)[i] == 'T') {
158 if (((*buff)[i + 1] == 'D') && ((*buff)[i + 2] == 'L') &&
159 ((*buff)[i + 3] == 'P')) {
160 tdlpMatch = 4;
161 break;
162 }
163 }
164 }
165 stillNeed = i - (curLen - 8);
166 /* Read enough of message to have the first 8 bytes (including ID). */
167 if (stillNeed != 0) {
168 curLen += stillNeed;
169 if ((limit >= 0) && (curLen > (size_t) limit)) {
170 errSprintf ("ERROR: Couldn't find type in %ld bytes\n", limit);
171 return -1;
172 }
173 if (*buffLen < curLen) {
174 *buffLen = curLen;
175 *buff = (char *) realloc ((void *) *buff,
176 *buffLen * sizeof (char));
177 }
178 if (fp.DataSourceFread((*buff) + (curLen - stillNeed), sizeof (char), stillNeed) != stillNeed) {
179 errSprintf ("ERROR: Ran out of file reading SECT0\n");
180 return -1;
181 }
182 }
183 }
184
185 /* curLen and (*buff) hold 8 bytes of section 0. */
186 curLen -= 8;
187 memcpy (&(sect0[0]), (*buff) + curLen, 4);
188 #ifdef DEBUG
189 #ifdef LITTLE_ENDIAN
190 myAssert ((sect0[0] == 1112101447L) || (sect0[0] == 1347175508L));
191 #else
192 myAssert ((sect0[0] == 1196575042L) || (sect0[0] == 1413762128L));
193 #endif
194 #endif
195 memcpy (&(sect0[1]), *buff + curLen + 4, 4);
196 /* Make sure we don't pass back part of "GRIB" in the buffer. */
197 (*buff)[curLen] = '\0';
198 *buffLen = curLen;
199
200 word.li = sect0[1];
201 if (tdlpMatch == 4) {
202 if (word.buffer[3] != 0) {
203 errSprintf ("ERROR: unexpected version of TDLP in SECT0\n");
204 return -2;
205 }
206 *version = -1;
207 /* Find out the GRIB Message Length */
208 *gribLen = GRIB_UNSIGN_INT3 (word.buffer[0], word.buffer[1],
209 word.buffer[2]);
210 /* Min message size: GRIB1=52, TDLP=59, GRIB2=86. */
211 if (*gribLen < 59) {
212 errSprintf ("TDLP length %ld was < 59?\n", *gribLen);
213 return -5;
214 }
215 } else if (word.buffer[3] == 1) {
216 *version = 1;
217 /* Find out the GRIB Message Length */
218 *gribLen = GRIB_UNSIGN_INT3 (word.buffer[0], word.buffer[1],
219 word.buffer[2]);
220 /* Min message size: GRIB1=52, TDLP=59, GRIB2=86. */
221 if (*gribLen < 52) {
222 errSprintf ("GRIB1 length %ld was < 52?\n", *gribLen);
223 return -5;
224 }
225 } else if (word.buffer[3] == 2) {
226 *version = 2;
227 /* Make sure we still have enough file for the rest of section 0. */
228 if (fp.DataSourceFread(sect0 + 2, sizeof (sInt4), 2) != 2) {
229 errSprintf ("ERROR: Ran out of file reading SECT0\n");
230 return -2;
231 }
232 if (sect0[2] != 0) {
233 errSprintf ("Most significant sInt4 of GRIB length was not 0?\n");
234 errSprintf ("This is either an error, or we have a single GRIB "
235 "message which is larger than 2^31 = 2,147,283,648 "
236 "bytes.\n");
237 return -4;
238 }
239 #ifdef LITTLE_ENDIAN
240 revmemcpy (gribLen, &(sect0[3]), sizeof (sInt4));
241 #else
242 *gribLen = sect0[3];
243 #endif
244 } else {
245 errSprintf ("ERROR: Not TDLPack, and Grib edition is not 1 or 2\n");
246 return -3;
247 }
248 return 0;
249 }
250
251 /*****************************************************************************
252 * FindGRIBMsg() -- Review 12/2002
253 *
254 * Arthur Taylor / MDL
255 *
256 * PURPOSE
257 * Jumps through a GRIB2 file looking for a specific message. Currently
258 * that message is determined by msgNum which is in the range of 1..n.
259 * In the future we may be searching based on projection or date.
260 *
261 * ARGUMENTS
262 * fp = The current GRIB2 file to look through. (Input)
263 * msgNum = Which message to look for. (Input)
264 * offset = Where in the file the message starts (this is before the
265 * wmo ASCII part if there is one.) (Output)
266 * curMsg = The current # of messages we have looked through. (In/Out)
267 *
268 * FILES/DATABASES:
269 * An already opened "GRIB2" File
270 *
271 * RETURNS: int (could use errSprintf())
272 * 0 = OK
273 * -1 = Problems reading Section 0.
274 * -2 = Ran out of file.
275 *
276 * HISTORY
277 * 11/2002 Arthur Taylor (MDL/RSIS): Created.
278 * 12/2002 (TK,AC,TB,&MS): Code Review.
279 * 6/2003 Matthew T. Kallio (matt@wunderground.com):
280 * "wmo" dimension increased to WMO_HEADER_LEN + 1 (for '\0' char)
281 * 8/2003 AAT: Removed dependence on offset and fileLen.
282 *
283 * NOTES
284 *****************************************************************************
285 */
FindGRIBMsg(DataSource & fp,int msgNum,sInt4 * offset,int * curMsg)286 int FindGRIBMsg (DataSource &fp, int msgNum, sInt4 *offset, int *curMsg)
287 {
288 int cnt; /* The current message we are looking at. */
289 char *buff; /* Holds the info between records. */
290 uInt4 buffLen; /* Length of info between records. */
291 sInt4 sect0[SECT0LEN_WORD]; /* Holds the current Section 0. */
292 uInt4 gribLen; /* Length of the current GRIB message. */
293 int version; /* Which version of GRIB is in this message. */
294 int c; /* Determine if end of the file without fileLen. */
295 sInt4 jump; /* How far to jump to get to past GRIB message. */
296
297 cnt = *curMsg + 1;
298 buff = NULL;
299 buffLen = 0;
300 while ((c = fp.DataSourceFgetc()) != EOF) {
301 fp.DataSourceUngetc(c);
302 if (cnt >= msgNum) {
303 /* 12/1/2004 version 1.63 forgot to free buff */
304 free (buff);
305 *curMsg = cnt;
306 return 0;
307 }
308 /* Read section 0 to find gribLen and wmoLen. */
309 if (ReadSECT0 (fp, &buff, &buffLen, GRIB_LIMIT, sect0, &gribLen,
310 &version) < 0) {
311 preErrSprintf ("Inside FindGRIBMsg\n");
312 free (buff);
313 return -1;
314 }
315 myAssert ((version == 1) || (version == 2) || (version == -1));
316 /* Continue on to the next grib message. */
317 if ((version == 1) || (version == -1)) {
318 jump = gribLen - 8;
319 } else {
320 jump = gribLen - 16;
321 }
322 fp.DataSourceFseek(jump, SEEK_CUR);
323 *offset = *offset + gribLen + buffLen;
324 cnt++;
325 }
326 free (buff);
327 *curMsg = cnt - 1;
328 /* Return -2 since we reached the end of file. This may not be an error
329 * (multiple file option). */
330 return -2;
331 /*
332 errSprintf ("ERROR: Ran out of file looking for msgNum %d.\n", msgNum);
333 errSprintf (" Current msgNum %d\n", cnt);
334 */
335 }
336
337 /*****************************************************************************
338 * FindSectLen2to7() --
339 *
340 * Arthur Taylor / MDL
341 *
342 * PURPOSE
343 * Looks through a GRIB message and finds out the maximum size of each
344 * section. Simpler if there is only one grid in the message.
345 *
346 * ARGUMENTS
347 * c_ipack = The current GRIB2 message. (Input)
348 * gribLen = Length of c_ipack. (Input)
349 * ns = Array of section lengths. (Output)
350 * sectNum = Which section to start with. (Input)
351 * curTot = on going total read from c_ipack. (Input)
352 * nd2x3 = Total number of grid points (Output)
353 * table50 = Type of packing used. (See code table 5.0) (GS5_SIMPLE = 0,
354 * GS5_CMPLX = 2, GS5_CMPLXSEC = 3) (Output)
355 *
356 * FILES/DATABASES: None
357 *
358 * RETURNS: int (could use errSprintf())
359 * 0 = OK
360 * -1 = Ran of data in a section
361 * -2 = Section not properly labeled.
362 *
363 * HISTORY
364 * 3/2003 AAT: Created
365 *
366 * NOTES
367 * 1) Assumes that the pack method of multiple grids are the same.
368 *****************************************************************************
369 */
FindSectLen2to7(char * c_ipack,sInt4 gribLen,sInt4 ns[8],char sectNum,sInt4 * curTot,sInt4 * nd2x3,short int * table50)370 static int FindSectLen2to7 (char *c_ipack, sInt4 gribLen, sInt4 ns[8],
371 char sectNum, sInt4 *curTot, sInt4 *nd2x3,
372 short int *table50)
373 {
374 sInt4 sectLen; /* The length of the current section. */
375 sInt4 li_temp; /* A temporary holder of sInt4s. */
376
377 if ((sectNum == 2) || (sectNum == 3)) {
378 /* Figure out the size of section 2 and 3. */
379 if (*curTot + 5 > gribLen) {
380 errSprintf ("ERROR: Ran out of data in Section 2 or 3\n");
381 return -1;
382 }
383 /* Handle optional section 2. */
384 if (c_ipack[*curTot + 4] == 2) {
385 MEMCPY_BIG (§Len, c_ipack + *curTot, 4);
386 *curTot = *curTot + sectLen;
387 if (ns[2] < sectLen)
388 ns[2] = sectLen;
389 if (*curTot + 5 > gribLen) {
390 errSprintf ("ERROR: Ran out of data in Section 3\n");
391 return -1;
392 }
393 }
394 /* Handle section 3. */
395 if (c_ipack[*curTot + 4] != 3) {
396 errSprintf ("ERROR: Section 3 labeled as %d\n",
397 c_ipack[*curTot + 4]);
398 return -2;
399 }
400 MEMCPY_BIG (§Len, c_ipack + *curTot, 4);
401 if (ns[3] < sectLen)
402 ns[3] = sectLen;
403 /* While we are here, grab the total number of grid points nd2x3. */
404 MEMCPY_BIG (&li_temp, c_ipack + *curTot + 6, 4);
405 if (*nd2x3 < li_temp)
406 *nd2x3 = li_temp;
407 *curTot = *curTot + sectLen;
408 }
409 /*
410 #ifdef DEBUG
411 printf ("Section len (2=%ld) (3=%ld)\n", ns[2], ns[3]);
412 #endif
413 */
414
415 /* Figure out the size of section 4. */
416 if (*curTot + 5 > gribLen) {
417 errSprintf ("ERROR: Ran out of data in Section 4\n");
418 return -1;
419 }
420 if (c_ipack[*curTot + 4] != 4) {
421 errSprintf ("ERROR: Section 4 labeled as %d\n", c_ipack[*curTot + 4]);
422 return -2;
423 }
424 MEMCPY_BIG (§Len, c_ipack + *curTot, 4);
425 if (ns[4] < sectLen)
426 ns[4] = sectLen;
427 *curTot = *curTot + sectLen;
428 /*
429 #ifdef DEBUG
430 printf ("Section len (4=%ld < %ld)\n", sectLen, ns[4]);
431 #endif
432 */
433
434 /* Figure out the size of section 5. */
435 if (*curTot + 5 > gribLen) {
436 errSprintf ("ERROR: Ran out of data in Section 5\n");
437 return -1;
438 }
439 if (c_ipack[*curTot + 4] != 5) {
440 errSprintf ("ERROR: Section 5 labeled as %d\n", c_ipack[*curTot + 4]);
441 return -2;
442 }
443 MEMCPY_BIG (§Len, c_ipack + *curTot, 4);
444 /* While we are here, grab the packing method. */
445 MEMCPY_BIG (table50, c_ipack + *curTot + 9, 2);
446 if (ns[5] < sectLen)
447 ns[5] = sectLen;
448 *curTot = *curTot + sectLen;
449 /*
450 #ifdef DEBUG
451 printf ("Section len (5=%ld < %ld)\n", sectLen, ns[5]);
452 #endif
453 */
454
455 /* Figure out the size of section 6. */
456 if (*curTot + 5 > gribLen) {
457 errSprintf ("ERROR: Ran out of data in Section 6\n");
458 return -1;
459 }
460 if (c_ipack[*curTot + 4] != 6) {
461 errSprintf ("ERROR: Section 6 labeled as %d\n", c_ipack[*curTot + 4]);
462 return -2;
463 }
464 MEMCPY_BIG (§Len, c_ipack + *curTot, 4);
465 if (ns[6] < sectLen)
466 ns[6] = sectLen;
467 *curTot = *curTot + sectLen;
468 /*
469 #ifdef DEBUG
470 printf ("Section len (6=%ld < %ld)\n", sectLen, ns[6]);
471 #endif
472 */
473
474 /* Figure out the size of section 7. */
475 if (*curTot + 5 > gribLen) {
476 errSprintf ("ERROR: Ran out of data in Section 7\n");
477 return -1;
478 }
479 if (c_ipack[*curTot + 4] != 7) {
480 errSprintf ("ERROR: Section 7 labeled as %d\n", c_ipack[*curTot + 4]);
481 return -2;
482 }
483 MEMCPY_BIG (§Len, c_ipack + *curTot, 4);
484 if (ns[7] < sectLen)
485 ns[7] = sectLen;
486 *curTot = *curTot + sectLen;
487 /*
488 #ifdef DEBUG
489 printf ("Section len (7=%ld < %ld)\n", sectLen, ns[7]);
490 #endif
491 */
492 return 0;
493 }
494
495 /*****************************************************************************
496 * FindSectLen() -- Review 12/2002
497 *
498 * Arthur Taylor / MDL
499 *
500 * PURPOSE
501 * Looks through a GRIB message and finds out how big each section is.
502 *
503 * ARGUMENTS
504 * c_ipack = The current GRIB2 message. (Input)
505 * gribLen = Length of c_ipack. (Input)
506 * ns = Array of section lengths. (Output)
507 * nd2x3 = Total number of grid points (Output)
508 * table50 = Type of packing used. (See code table 5.0) (GS5_SIMPLE = 0,
509 * GS5_CMPLX = 2, GS5_CMPLXSEC = 3) (Output)
510 *
511 * FILES/DATABASES: None
512 *
513 * RETURNS: int (could use errSprintf())
514 * 0 = OK
515 * -1 = Ran of data in a section
516 * -2 = Section not properly labeled.
517 *
518 * HISTORY
519 * 9/2002 Arthur Taylor (MDL/RSIS): Created.
520 * 11/2002 AAT: Updated.
521 * 12/2002 (TK,AC,TB,&MS): Code Review.
522 * 3/2003 AAT: Made it handle multiple grids in the same GRIB2 message.
523 * 5/2003 AAT: Bug: Initialized size of section 2..6 to -1, instead
524 * of 2..7.
525 *
526 * NOTES
527 * 1) Assumes that the pack method of multiple grids are the same.
528 *****************************************************************************
529 */
FindSectLen(char * c_ipack,sInt4 gribLen,sInt4 ns[8],sInt4 * nd2x3,short int * table50)530 static int FindSectLen (char *c_ipack, sInt4 gribLen, sInt4 ns[8],
531 sInt4 *nd2x3, short int *table50)
532 {
533 sInt4 curTot; /* Where we are in the current GRIB message. */
534 char sectNum; /* Which section we are working with. */
535 int ans; /* The return error code of FindSectLen2to7. */
536 sInt4 sectLen; /* The length of the current section. */
537 int i; /* counter as we init ns[]. */
538
539 ns[0] = SECT0LEN_WORD * 4;
540 curTot = ns[0];
541
542 /* Figure out the size of section 1. */
543 if (curTot + 5 > gribLen) {
544 errSprintf ("ERROR: Ran out of data in Section 1\n");
545 return -1;
546 }
547 if (c_ipack[curTot + 4] != 1) {
548 errSprintf ("ERROR: Section 1 labeled as %d\n", c_ipack[curTot + 4]);
549 return -2;
550 }
551 MEMCPY_BIG (&(ns[1]), c_ipack + curTot, 4);
552 curTot += ns[1];
553 /*
554 #ifdef DEBUG
555 printf ("Section len (0=%ld) (1=%ld)\n", ns[0], ns[1]);
556 #endif
557 */
558 sectNum = 2;
559 for (i = 2; i < 8; i++) {
560 ns[i] = -1;
561 }
562 *nd2x3 = -1;
563 do {
564 if ((ans = FindSectLen2to7 (c_ipack, gribLen, ns, sectNum, &curTot,
565 nd2x3, table50)) != 0) {
566 return ans;
567 }
568 /* Try to read section 8. If it is "7777" == 926365495 regardless of
569 * endian'ness then we have a simple message, otherwise it is complex,
570 * and we need to read more. */
571 memcpy (§Len, c_ipack + curTot, 4);
572 if (sectLen == 926365495L) {
573 sectNum = 8;
574 } else {
575 sectNum = c_ipack[curTot + 4];
576 if ((sectNum < 2) || (sectNum > 7)) {
577 errSprintf ("ERROR (FindSectLen): Couldn't find the end of the "
578 "message\n");
579 errSprintf ("and it doesn't appear to repeat sections.\n");
580 errSprintf ("so it is probably an ASCII / binary bug\n");
581 errSprintf ("Max Sect Lengths: %ld %ld %ld %ld %ld %ld %ld"
582 " %ld\n", ns[0], ns[1], ns[2], ns[3], ns[4], ns[5],
583 ns[6], ns[7]);
584 return -2;
585 }
586 }
587 } while (sectNum != 8);
588 return 0;
589 }
590
591 /*****************************************************************************
592 * IS_Init() -- Review 12/2002
593 *
594 * Arthur Taylor / MDL
595 *
596 * PURPOSE
597 * Initialize the IS data structure. The IS_dataType is used to organize
598 * and allocate all the arrays that the unpack library uses.
599 * This makes an initial guess for the size of the arrays, and we use
600 * realloc to increase the size if needed. The write up: "UNPK_GRIB2
601 * 3/15/02" by Bryon Lawrence, Bob Glahn, David Rudack suggested these numbers
602 *
603 * ARGUMENTS
604 * is = The data structure to initialize. (Output)
605 *
606 * FILES/DATABASES: None
607 *
608 * RETURNS: void
609 *
610 * HISTORY
611 * 9/2002 Arthur Taylor (MDL/RSIS): Created.
612 * 11/2002 AAT : Updated.
613 * 12/2002 (TK,AC,TB,&MS): Code Review.
614 *
615 * NOTES
616 * 1) Numbers not found in document were discused with Bob Glahn on 8/29/2002
617 * 2) Possible exceptions:
618 * template 3.120 could need ns[3] = 1600
619 * template 4.30 could need a different ns4.
620 * 3) sizeof(float) == sizeof(sInt4), and unpacker does not use both ain
621 * and iain, so it is possible to have ain and iain point to the same
622 * memory. Not sure if this is safe, so I haven't done it.
623 *****************************************************************************
624 */
IS_Init(IS_dataType * is)625 void IS_Init (IS_dataType *is)
626 {
627 int i; /* A simple loop counter. */
628 is->ns[0] = 16;
629 is->ns[1] = 21;
630 is->ns[2] = 7;
631 is->ns[3] = 96;
632 is->ns[4] = 130; /* 60->130 in case there are some S4 time intervals */
633 is->ns[5] = 49;
634 is->ns[6] = 6;
635 is->ns[7] = 8;
636 for (i = 0; i < 8; i++) {
637 is->is[i] = (sInt4 *) calloc (is->ns[i], sizeof (sInt4));
638 }
639 /* Allocate grid memory. */
640 is->nd2x3 = 0;
641 is->iain = NULL;
642 is->ib = NULL;
643 /* Allocate section 2 int memory. */
644 is->nidat = 0;
645 is->idat = NULL;
646 /* Allocate section 2 float memory. */
647 is->nrdat = 0;
648 is->rdat = NULL;
649 /* Allocate storage for ipack. */
650 is->ipackLen = 0;
651 is->ipack = NULL;
652 }
653
654 /*****************************************************************************
655 * IS_Free() -- Review 12/2002
656 *
657 * Arthur Taylor / MDL
658 *
659 * PURPOSE
660 * Free the memory allocated in the IS data structure.
661 * The IS_dataType is used to organize and allocate all the arrays that the
662 * unpack library uses.
663 *
664 * ARGUMENTS
665 * is = The data structure to Free. (Output)
666 *
667 * FILES/DATABASES: None
668 *
669 * RETURNS: void
670 *
671 * HISTORY
672 * 9/2002 Arthur Taylor (MDL/RSIS): Created.
673 * 11/2002 AAT : Updated.
674 * 12/2002 (TK,AC,TB,&MS): Code Review.
675 *
676 * NOTES
677 *****************************************************************************
678 */
IS_Free(IS_dataType * is)679 void IS_Free (IS_dataType *is)
680 {
681 int i; /* A simple loop counter. */
682 for (i = 0; i < 8; i++) {
683 free (is->is[i]);
684 is->is[i] = NULL;
685 is->ns[i] = 0;
686 }
687 /* Free grid memory. */
688 free (is->iain);
689 is->iain = NULL;
690 free (is->ib);
691 is->ib = NULL;
692 is->nd2x3 = 0;
693 /* Free section 2 int memory. */
694 free (is->idat);
695 is->idat = NULL;
696 is->nidat = 0;
697 /* Free section 2 float memory. */
698 free (is->rdat);
699 is->rdat = NULL;
700 is->nrdat = 0;
701 /* Free storage for ipack. */
702 free (is->ipack);
703 is->ipack = NULL;
704 is->ipackLen = 0;
705 }
706
707 /*****************************************************************************
708 * ReadGrib2Record() -- Review 12/2002
709 *
710 * Arthur Taylor / MDL
711 *
712 * PURPOSE
713 * Reads a GRIB2 message from a file which is already opened and is pointing
714 * at the correct message. It reads in the message storing the results in
715 * Grib_Data which is of size grib_DataLen. If needed, it increases
716 * grib_DataLen enough to fit the current message's grid. It converts (if
717 * appropriate) the data in Grib_Data to the units specified in f_unit.
718 *
719 * In addition it updates offset, and stores the meta data returned by the
720 * unpacker library in both IS, and (after parsing it) in meta.
721 *
722 * Note: It expects meta and IS to already be initialized through calls to
723 * MetaInit(&meta) and IS_Init(&is) respectively.
724 *
725 * ARGUMENTS
726 * fp = An opened GRIB2 file already at the correct message. (Input)
727 * fileLen = Length of the opened file. (Input)
728 * f_unit = 0 use GRIB2 units, 1 use English, 2 use metric. (Input)
729 * Grib_Data = The read in GRIB2 grid. (Output)
730 * grib_DataLen = Size of Grib_Data. (Output)
731 * meta = A filled in meta structure (Output)
732 * IS = The structure containing all the arrays that the
733 * unpacker uses (Output)
734 * subgNum = Which subgrid in the GRIB2 message is of interest.
735 * (0 = first grid), if it can't find message subgNum,
736 * returns -5, and an error message (Input)
737 * majEarth = Used to override the GRIB major axis of earth. (Input)
738 * minEarth = Used to override the GRIB minor axis of earth. (Input)
739 * simpVer = The version of the simple weather code to use when parsing
740 * the WxString. (Input)
741 * f_endMsg = 1 means we finished reading the previous GRIB message, or
742 * there was no previous GRIB message. 0 means that we need
743 * to read a subgrid of the previous message. (Input/Output)
744 * lwlt, uprt = If the lat is not -100, then lwlt, and uprt define a
745 * subgrid that the user is interested in. Get the map
746 * projection out of the GRIB2 message, and do everything
747 * on the subgrid. (if lwlt, and uprt are not "correct", the
748 * lat/lons may get swapped) (Input/Output)
749 *
750 * FILES/DATABASES:
751 * An already opened "GRIB2" File
752 *
753 * RETURNS: int (could use errSprintf())
754 * 0 = OK
755 * -1 = Problems in section 0
756 * -2 = Problems figuring out the Section Lengths.
757 * -3 = Error returned by unpack library.
758 * -4 = Problems parsing the Meta Data.
759 *
760 * HISTORY
761 * 9/2002 Arthur Taylor (MDL/RSIS): Created.
762 * 11/2002 AAT: Updated.
763 * 12/2002 (TK,AC,TB,&MS): Code Review.
764 * 1/2003 AAT: It wasn't error coded 208, but rather 202 to look for.
765 * 3/2003 AAT: Modified handling of section 2 stuff (no loop)
766 * 3/2003 AAT: Added ability to handle multiple grids in same message.
767 * 4/2003 AAT: Added ability to call GRIB1 decoder for GRIB1 messages.
768 * 5/2003 AAT: Update the offset for ReadGrib1.
769 * 6/2003 Matthew T. Kallio (matt@wunderground.com):
770 * "wmo" dimension increased to WMO_HEADER_LEN + 1 (for '\0' char)
771 * 7/2003 AAT: switched to checking against element name for Wx instead
772 * of pds2.sect2.ptrType == GS2_WXTYPE
773 * 7/2003 AAT: Allowed user to override the radius of earth.
774 * 8/2003 AAT: Removed dependence on fileLen and offset.
775 * 2/2004 AAT: Added "f_endMsg" logic.
776 * 2/2004 AAT: Added subgrid potential.
777 * 2/2004 AAT: Added maj/min Earth override.
778 *
779 * NOTES
780 * 1) Reason ns[7] is not MAX (IS.ns[], local_ns[]) is because local_ns[7]
781 * is size of the packed message, but ns[7] refers to the returned meta
782 * data which unpacker library found in section 7, which is a lot smaller.
783 * 2) Problem: MDL's sect2 is packed and we have no idea how large it is
784 * when unpacked. So we allocate room for 4000 sInt4s and 500 floats.
785 * We then check 'jer' for error "202", if we find it we double the size
786 * and call the unpacker again.
787 * 3/26/2003: Changed this to be: try once with size
788 * = max (32 * packed size, 4000)
789 * Should be fewer calls (more memory intensive) same result, since we had
790 * been doubling it 5 times.
791 * 3) For Complex second order packing (GS5_CMPLXSEC) the unpacker needs nd5
792 * (which is size of message) to be >= nd2x3 (size of grid).
793 * 3a) Appears to also need this if simple packing, and has a bitmap.
794 * 4) inew = 1: Currently we only expect 1 grid in 1 GRIB message, although
795 * the library does allow for multiple grids in a GRIB message.
796 * 5) iclean = 1: This only maters if there is bitmap data, otherwise it is
797 * ignored. For bitmap data, if == 0, it embeds the given values for
798 * xmissp, and xmisss. We don't embed because we don't know what to set
799 * xmissp or xmisss to. Instead after we know the range, we choose a value
800 * and walk through the bitmap setting grib_Data appropriately.
801 * 5a) iclean = 0; This is because we do want the missing values embeded.
802 * that is we want the missing values to be place holders.
803 * 6) f_endMsg is true if in the past we either completed reading a message,
804 * or we haven't read any messages. In either case we need to read the
805 * next message from file. If f_endMsg is false, then there is more to read
806 * from IS->ipack, so we don't want to throw it out, nor have to re-read
807 * ipack from disk.
808 *
809 * Question: Should we double ns[2] when we double nrdat, and nidat?
810 *****************************************************************************
811 */
812 #define SECT2_INIT_SIZE 4000
813 #define UNPK_NUM_ERRORS 22
ReadGrib2Record(DataSource & fp,sChar f_unit,double ** Grib_Data,uInt4 * grib_DataLen,grib_MetaData * meta,IS_dataType * IS,int subgNum,double majEarth,double minEarth,int simpVer,sInt4 * f_endMsg,CPL_UNUSED LatLon * lwlf,CPL_UNUSED LatLon * uprt)814 int ReadGrib2Record (DataSource &fp, sChar f_unit, double **Grib_Data,
815 uInt4 *grib_DataLen, grib_MetaData *meta,
816 IS_dataType *IS, int subgNum, double majEarth,
817 double minEarth, int simpVer, sInt4 *f_endMsg,
818 CPL_UNUSED LatLon *lwlf,
819 CPL_UNUSED LatLon *uprt)
820 {
821 sInt4 l3264b; /* Number of bits in a sInt4. Needed by FORTRAN
822 * unpack library to determine if system has a 4
823 * byte_ sInt4 or an 8 byte sInt4. */
824 char *buff; /* Holds the info between records. */
825 uInt4 buffLen; /* Length of info between records. */
826 sInt4 sect0[SECT0LEN_WORD]; /* Holds the current Section 0. */
827 uInt4 gribLen; /* Length of the current GRIB message. */
828 sInt4 nd5; /* Size of grib message rounded up to the nearest
829 * sInt4. */
830 char *c_ipack; /* A char ptr to the message stored in IS->ipack */
831 sInt4 local_ns[8]; /* Local copy of section lengths. */
832 sInt4 nd2x3; /* Total number of grid points. */
833 short int table50; /* Type of packing used. (See code table 5.0)
834 * (GS5_SIMPLE==0, GS5_CMPLX==2, GS5_CMPLXSEC==3) */
835 sInt4 nidat; /* Size of section 2 if it contains integer data. */
836 sInt4 nrdat; /* Size of section 2 if it contains float data. */
837 sInt4 inew; /* 1 if this is the first grid we are reading. 0 if
838 * this is the second or later grid from the same
839 * GRIB message. */
840 sInt4 iclean = 0; /* 0 embed the missing values, 1 don't. */
841 int j; /* Counter used to find the desired subgrid. */
842 sInt4 kfildo = 5; /* FORTRAN Unit number for diagnostic info. Ignored,
843 * unless library is compiled a particular way. */
844 sInt4 ibitmap; /* 0 means no bitmap returned, otherwise 1. */
845 float xmissp; /* The primary missing value. If iclean = 0, this
846 * value is embeded in grid, otherwise it is the
847 * value returned from the GRIB message. */
848 float xmisss; /* The secondary missing value. If iclean = 0, this
849 * value is embeded in grid, otherwise it is the
850 * value returned from the GRIB message. */
851 sInt4 jer[UNPK_NUM_ERRORS * 2]; /* Any Error codes along with their *
852 * severity levels generated using the *
853 * unpack GRIB2 library. */
854 sInt4 ndjer = UNPK_NUM_ERRORS; /* The number of rows in JER( ). */
855 sInt4 kjer; /* The actual number of errors returned in JER. */
856 size_t i; /* counter as we loop through jer. */
857 double unitM, unitB; /* values in y = m x + b used for unit conversion. */
858 char unitName[15]; /* Holds the string name of the current unit. */
859 int unitLen; /* String length of string name of current unit. */
860 int version; /* Which version of GRIB is in this message. */
861 sInt4 cnt; /* Used to help compact the weather table. */
862 int x1, y1; /* The original grid coordinates of the lower left
863 * corner of the subgrid. */
864 int x2, y2; /* The original grid coordinates of the upper right
865 * corner of the subgrid. */
866 uChar f_subGrid; /* True if we have a subgrid. */
867 sInt4 Nx, Ny; /* original size of the data. */
868
869 /*
870 * f_endMsg is 1 if in the past we either completed reading a message,
871 * or we haven't read any messages. In either case we need to read the
872 * next message from file.
873 * If f_endMsg is false, then there is more to read from IS->ipack, so we
874 * don't want to throw it out, nor have to re-read ipack from disk.
875 */
876 l3264b = sizeof (sInt4) * 8;
877 buff = NULL;
878 buffLen = 0;
879 if (*f_endMsg == 1) {
880 if (ReadSECT0 (fp, &buff, &buffLen, -1, sect0, &gribLen, &version) < 0) {
881 preErrSprintf ("Inside ReadGrib2Record\n");
882 free (buff);
883 return -1;
884 }
885 meta->GribVersion = version;
886 if (version == 1) {
887 if (ReadGrib1Record (fp, f_unit, Grib_Data, grib_DataLen, meta, IS,
888 sect0, gribLen, majEarth, minEarth) != 0) {
889 preErrSprintf ("Problems with ReadGrib1Record called by "
890 "ReadGrib2Record\n");
891 free (buff);
892 return -1;
893 }
894 *f_endMsg = 1;
895 free (buff);
896 return 0;
897 } else if (version == -1) {
898 if (ReadTDLPRecord (fp, Grib_Data, grib_DataLen, meta, IS,
899 sect0, gribLen, majEarth, minEarth) != 0) {
900 preErrSprintf ("Problems with ReadGrib1Record called by "
901 "ReadGrib2Record\n");
902 free (buff);
903 return -1;
904 }
905 free (buff);
906 return 0;
907 }
908
909 /*
910 * Make room for entire message, and read it in.
911 */
912 /* nd5 needs to be gribLen in (sInt4) units rounded up. */
913 nd5 = (gribLen + 3) / 4;
914 if (nd5 > IS->ipackLen) {
915 IS->ipackLen = nd5;
916 IS->ipack = (sInt4 *) realloc ((void *) (IS->ipack),
917 (IS->ipackLen) * sizeof (sInt4));
918 }
919 c_ipack = (char *) IS->ipack;
920 /* Init last sInt4 to 0, to make sure that the padded bytes are 0. */
921 IS->ipack[nd5 - 1] = 0;
922 /* Init first 4 sInt4 to sect0. */
923 memcpy (c_ipack, sect0, SECT0LEN_WORD * 4);
924 /* Read in the rest of the message. */
925 if (fp.DataSourceFread (c_ipack + SECT0LEN_WORD * 4, sizeof (char),
926 (gribLen - SECT0LEN_WORD * 4)) != (gribLen - SECT0LEN_WORD * 4)) {
927 errSprintf ("GribLen = %ld, SECT0Len_WORD = %d\n", gribLen,
928 SECT0LEN_WORD);
929 errSprintf ("Ran out of file\n");
930 free (buff);
931 return -1;
932 }
933
934 /*
935 * Make sure the arrays are large enough for call to unpacker library.
936 */
937 /* FindSectLen Does not want (ipack / c_ipack) word swapped, because
938 * that would make it much more confusing to find bytes in c_ipack. */
939 if (FindSectLen (c_ipack, gribLen, local_ns, &nd2x3, &table50) < 0) {
940 preErrSprintf ("Inside ReadGrib2Record.. Calling FindSectLen\n");
941 free (buff);
942 return -2;
943 }
944
945 /* Make sure all 'is' arrays except ns[7] are MAX (IS.ns[] ,
946 * local_ns[]). See note 1 for reason to exclude ns[7] from MAX (). */
947 for (i = 0; i < 7; i++) {
948 if (local_ns[i] > IS->ns[i]) {
949 IS->ns[i] = local_ns[i];
950 IS->is[i] = (sInt4 *) realloc ((void *) (IS->is[i]),
951 IS->ns[i] * sizeof (sInt4));
952 }
953 }
954
955 /* Allocate room for sect 2. If local_ns[2] = -1 there is no sect 2. */
956 if (local_ns[2] == -1) {
957 nidat = 10;
958 nrdat = 10;
959 } else {
960 /*
961 * See note 2) We have a section 2, so use:
962 * MAX (32 * local_ns[2],SECT2_INTSIZE)
963 * and MAX (32 * local_ns[2],SECT2_FLOATSIZE)
964 * for size of section 2 unpacked.
965 */
966 nidat = (32 * local_ns[2] < SECT2_INIT_SIZE) ? SECT2_INIT_SIZE :
967 32 * local_ns[2];
968 nrdat = nidat;
969 }
970 if (nidat > IS->nidat) {
971 IS->nidat = nidat;
972 IS->idat = (sInt4 *) realloc ((void *) IS->idat,
973 IS->nidat * sizeof (sInt4));
974 }
975 if (nrdat > IS->nrdat) {
976 IS->nrdat = nrdat;
977 IS->rdat = (float *) realloc ((void *) IS->rdat,
978 IS->nrdat * sizeof (float));
979 }
980 /* Make sure we have room for the GRID part of the output. */
981 if (nd2x3 > IS->nd2x3) {
982 IS->nd2x3 = nd2x3;
983 IS->iain = (sInt4 *) realloc ((void *) IS->iain,
984 IS->nd2x3 * sizeof (sInt4));
985 IS->ib = (sInt4 *) realloc ((void *) IS->ib,
986 IS->nd2x3 * sizeof (sInt4));
987 }
988 /* See note 3) If table50 == 3, unpacker library needs nd5 >= nd2x3. */
989 if ((table50 == 3) || (table50 == 0)) {
990 if (nd5 < nd2x3) {
991 nd5 = nd2x3;
992 if (nd5 > IS->ipackLen) {
993 IS->ipackLen = nd5;
994 IS->ipack = (sInt4 *) realloc ((void *) (IS->ipack),
995 IS->ipackLen * sizeof (sInt4));
996 }
997 /* Don't need to do the following, but we do in case code
998 * changes. */
999 c_ipack = (char *) IS->ipack;
1000 }
1001 }
1002 IS->nd5 = nd5;
1003 /* Unpacker library requires ipack to be MSB. */
1004 /*
1005 #ifdef DEBUG
1006 if (1==1) {
1007 FILE *fp = fopen ("test.bin", "wb");
1008 fwrite (IS->ipack, sizeof (sInt4), IS->nd5, fp);
1009 fclose (fp);
1010 }
1011 #endif
1012 */
1013 #ifdef LITTLE_ENDIAN
1014 memswp (IS->ipack, sizeof (sInt4), IS->nd5);
1015 #endif
1016 } else {
1017 gribLen = IS->ipack[3];
1018 }
1019 free (buff);
1020
1021 /* Loop through the grib message looking for the subgNum grid. subgNum
1022 * goes from 0 to n-1. */
1023 for (j = 0; j <= subgNum; j++) {
1024 if (j == 0) {
1025 inew = 1;
1026 } else {
1027 inew = 0;
1028 }
1029
1030 /* Note we are getting data back either as a float or an int, but not
1031 * both, so we don't need to allocated room for both. */
1032 unpk_grib2 (&kfildo, (float *) (IS->iain), IS->iain, &(IS->nd2x3),
1033 IS->idat, &(IS->nidat), IS->rdat, &(IS->nrdat), IS->is[0],
1034 &(IS->ns[0]), IS->is[1], &(IS->ns[1]), IS->is[2],
1035 &(IS->ns[2]), IS->is[3], &(IS->ns[3]), IS->is[4],
1036 &(IS->ns[4]), IS->is[5], &(IS->ns[5]), IS->is[6],
1037 &(IS->ns[6]), IS->is[7], &(IS->ns[7]), IS->ib, &ibitmap,
1038 IS->ipack, &(IS->nd5), &xmissp, &xmisss, &inew, &iclean,
1039 &l3264b, f_endMsg, jer, &ndjer, &kjer);
1040 /*
1041 * Check for error messages...
1042 * If we get an error message, print it, and return.
1043 */
1044 for (i = 0; i < (uInt4) kjer; i++) {
1045 if (jer[ndjer + i] == 0) {
1046 /* no error. */
1047 } else if (jer[ndjer + i] == 1) {
1048 /* Warning. */
1049 #ifdef DEBUG
1050 printf ("Warning: Unpack library warning code (%d %d)\n",
1051 jer[i], jer[ndjer + i]);
1052 #endif
1053 } else {
1054 /* BAD Error. */
1055 errSprintf ("ERROR: Unpack library error code (%ld %ld)\n",
1056 jer[i], jer[ndjer + i]);
1057 return -3;
1058 }
1059 }
1060 }
1061
1062 /* Parse the meta data out. */
1063 if (MetaParse (meta, IS->is[0], IS->ns[0], IS->is[1], IS->ns[1],
1064 IS->is[2], IS->ns[2], IS->rdat, IS->nrdat, IS->idat,
1065 IS->nidat, IS->is[3], IS->ns[3], IS->is[4], IS->ns[4],
1066 IS->is[5], IS->ns[5], gribLen, xmissp, xmisss, simpVer)
1067 != 0) {
1068 #ifdef DEBUG
1069 FILE *fp;
1070 if ((fp = fopen ("dump.is0", "wt")) != NULL) {
1071 for (i = 0; i < 8; i++) {
1072 fprintf (fp, "---Section %d---\n", (int) i);
1073 for (j = 1; j <= IS->ns[i]; j++) {
1074 fprintf (fp, "IS%d Item %d = %d\n", (int) i, (int) j, IS->is[i][j - 1]);
1075 }
1076 }
1077 fclose (fp);
1078 }
1079 #endif
1080 preErrSprintf ("Inside ReadGrib2Record.. Problems in MetaParse\n");
1081 return -4;
1082 }
1083
1084 if ((majEarth > 6000) && (majEarth < 7000)) {
1085 if ((minEarth > 6000) && (minEarth < 7000)) {
1086 meta->gds.f_sphere = 0;
1087 meta->gds.majEarth = majEarth;
1088 meta->gds.minEarth = minEarth;
1089 } else {
1090 meta->gds.f_sphere = 1;
1091 meta->gds.majEarth = majEarth;
1092 meta->gds.minEarth = majEarth;
1093 }
1094 }
1095
1096 /* Figure out an equation to pass to ParseGrid to convert the units for
1097 * this grid. */
1098 /*
1099 if (ComputeUnit (meta->pds2.prodType, meta->pds2.sect4.templat,
1100 meta->pds2.sect4.cat, meta->pds2.sect4.subcat, f_unit,
1101 &unitM, &unitB, unitName) == 0) {
1102 */
1103 if (ComputeUnit (meta->convert, meta->unitName, f_unit, &unitM, &unitB,
1104 unitName) == 0) {
1105 unitLen = strlen (unitName);
1106 meta->unitName = (char *) realloc ((void *) (meta->unitName),
1107 1 + unitLen * sizeof (char));
1108 strncpy (meta->unitName, unitName, unitLen);
1109 meta->unitName[unitLen] = '\0';
1110 }
1111
1112 /* compute the subgrid. */
1113 /*
1114 if ((lwlf->lat != -100) && (uprt->lat != -100)) {
1115 Nx = meta->gds.Nx;
1116 Ny = meta->gds.Ny;
1117 if (computeSubGrid (lwlf, &x1, &y1, uprt, &x2, &y2, &(meta->gds),
1118 &newGds) != 0) {
1119 preErrSprintf ("ERROR: In compute subgrid.\n");
1120 return 1;
1121 }
1122 // I couldn't decide if I should "permanently" change the GDS or not.
1123 // when I wrote computeSubGrid. If next line stays, really should
1124 // rewrite computeSubGrid.
1125 memcpy (&(meta->gds), &newGds, sizeof (gdsType));
1126 f_subGrid = 1;
1127 } else {
1128 Nx = meta->gds.Nx;
1129 Ny = meta->gds.Ny;
1130 x1 = 1;
1131 x2 = Nx;
1132 y1 = 1;
1133 y2 = Ny;
1134 f_subGrid = 0;
1135 }
1136 */
1137 Nx = meta->gds.Nx;
1138 Ny = meta->gds.Ny;
1139 x1 = 1;
1140 x2 = Nx;
1141 y1 = 1;
1142 y2 = Ny;
1143 f_subGrid = 0;
1144
1145 /* Figure out if we need iain or ain, and set it to Grib_Data. At the
1146 * same time handle any bitmaps, and compute some statistics. */
1147 if ((f_subGrid) && (meta->gds.scan != 64)) {
1148 errSprintf ("Can not do a subgrid of non scanmode 64 grid yet.\n");
1149 return -3;
1150 }
1151
1152 if (strcmp (meta->element, "Wx") != 0) {
1153 ParseGrid (&(meta->gridAttrib), Grib_Data, grib_DataLen, Nx, Ny,
1154 meta->gds.scan, IS->iain, ibitmap, IS->ib, unitM, unitB, 0,
1155 NULL, f_subGrid, x1, y1, x2, y2);
1156 } else {
1157 /* Handle weather grid. ParseGrid looks up the values... If they are
1158 * "<Invalid>" it sets it to missing (or creates one). If the table
1159 * entry is used it sets f_valid to 2. */
1160 ParseGrid (&(meta->gridAttrib), Grib_Data, grib_DataLen, Nx, Ny,
1161 meta->gds.scan, IS->iain, ibitmap, IS->ib, unitM, unitB, 1,
1162 (sect2_WxType *) &(meta->pds2.sect2.wx), f_subGrid, x1, y1,
1163 x2, y2);
1164
1165 /* compact the table to only those which are actually used. */
1166 cnt = 0;
1167 for (i = 0; i < meta->pds2.sect2.wx.dataLen; i++) {
1168 if (meta->pds2.sect2.wx.ugly[i].f_valid == 2) {
1169 meta->pds2.sect2.wx.ugly[i].validIndex = cnt;
1170 cnt++;
1171 } else if (meta->pds2.sect2.wx.ugly[i].f_valid == 3) {
1172 meta->pds2.sect2.wx.ugly[i].f_valid = 0;
1173 meta->pds2.sect2.wx.ugly[i].validIndex = cnt;
1174 cnt++;
1175 } else {
1176 meta->pds2.sect2.wx.ugly[i].validIndex = -1;
1177 }
1178 }
1179 }
1180
1181 /* Figure out some other non-section oriented meta data. */
1182 /* strftime (meta->refTime, 20, "%Y%m%d%H%M",
1183 gmtime (&(meta->pds2.refTime)));
1184 */
1185 Clock_Print (meta->refTime, 20, meta->pds2.refTime, "%Y%m%d%H%M", 0);
1186 /*
1187 strftime (meta->validTime, 20, "%Y%m%d%H%M",
1188 gmtime (&(meta->pds2.sect4.validTime)));
1189 */
1190 Clock_Print (meta->validTime, 20, meta->pds2.sect4.validTime,
1191 "%Y%m%d%H%M", 0);
1192
1193 meta->deltTime = (sInt4) (meta->pds2.sect4.validTime - meta->pds2.refTime);
1194
1195 return 0;
1196 }
1197