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 (&sectLen, 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 (&sectLen, 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 (&sectLen, 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 (&sectLen, 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 (&sectLen, 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 (&sectLen, 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 (&sectLen, 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