LCOV - code coverage report
Current view: directory - frmts/grib/degrib18/degrib - degrib2.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 358 216 60.3 %
Date: 2010-01-09 Functions: 7 6 85.7 %

       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                 :  */
     113              27 : 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              27 :    uChar gribMatch = 0; /* Counts how many letters in GRIB we've matched. */
     122              27 :    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              27 :    curLen = 8;
     133              27 :    if (*buffLen < curLen) {
     134              26 :       *buffLen = curLen;
     135              26 :       *buff = (char *) realloc ((void *) *buff, *buffLen * sizeof (char));
     136                 :    }
     137              27 :    if (fp.DataSourceFread(*buff, sizeof (char), curLen) != curLen) {
     138               0 :       errSprintf ("ERROR: Couldn't find 'GRIB' or 'TDLP'\n");
     139               0 :       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             145 :    while ((tdlpMatch != 4) && (gribMatch != 4)) {
     150             411 :       for (i = curLen - 8; i + 3 < curLen; i++) {
     151             347 :          if ((*buff)[i] == 'G') {
     152              54 :             if (((*buff)[i + 1] == 'R') && ((*buff)[i + 2] == 'I') &&
     153              27 :                 ((*buff)[i + 3] == 'B')) {
     154              27 :                gribMatch = 4;
     155              27 :                break;
     156                 :             }
     157             320 :          } else if ((*buff)[i] == 'T') {
     158               0 :             if (((*buff)[i + 1] == 'D') && ((*buff)[i + 2] == 'L') &&
     159               0 :                 ((*buff)[i + 3] == 'P')) {
     160               0 :                tdlpMatch = 4;
     161               0 :                break;
     162                 :             }
     163                 :          }
     164                 :       }
     165              91 :       stillNeed = i - (curLen - 8);
     166                 :       /* Read enough of message to have the first 8 bytes (including ID). */
     167              91 :       if (stillNeed != 0) {
     168              64 :          curLen += stillNeed;
     169              64 :          if ((limit >= 0) && (curLen > (size_t) limit)) {
     170               0 :             errSprintf ("ERROR: Couldn't find type in %ld bytes\n", limit);
     171               0 :             return -1;
     172                 :          }
     173              64 :          if (*buffLen < curLen) {
     174              56 :             *buffLen = curLen;
     175                 :             *buff = (char *) realloc ((void *) *buff,
     176              56 :                                       *buffLen * sizeof (char));
     177                 :          }
     178              64 :          if (fp.DataSourceFread((*buff) + (curLen - stillNeed), sizeof (char), stillNeed) != stillNeed) {
     179               0 :             errSprintf ("ERROR: Ran out of file reading SECT0\n");
     180               0 :             return -1;
     181                 :          }
     182                 :       }
     183                 :    }
     184                 : 
     185                 :    /* curLen and (*buff) hold 8 bytes of section 0. */
     186              27 :    curLen -= 8;
     187              27 :    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              27 :    memcpy (&(sect0[1]), *buff + curLen + 4, 4);
     196                 :    /* Make sure we don't pass back part of "GRIB" in the buffer. */
     197              27 :    (*buff)[curLen] = '\0';
     198              27 :    *buffLen = curLen;
     199                 : 
     200              27 :    word.li = sect0[1];
     201              27 :    if (tdlpMatch == 4) {
     202               0 :       if (word.buffer[3] != 0) {
     203               0 :          errSprintf ("ERROR: unexpected version of TDLP in SECT0\n");
     204               0 :          return -2;
     205                 :       }
     206               0 :       *version = -1;
     207                 :       /* Find out the GRIB Message Length */
     208               0 :       *gribLen = GRIB_UNSIGN_INT3 (word.buffer[0], word.buffer[1],
     209               0 :                                    word.buffer[2]);
     210                 :       /* Min message size: GRIB1=52, TDLP=59, GRIB2=86. */
     211               0 :       if (*gribLen < 59) {
     212               0 :          errSprintf ("TDLP length %ld was < 59?\n", *gribLen);
     213               0 :          return -5;
     214                 :       }
     215              27 :    } else if (word.buffer[3] == 1) {
     216              22 :       *version = 1;
     217                 :       /* Find out the GRIB Message Length */
     218              66 :       *gribLen = GRIB_UNSIGN_INT3 (word.buffer[0], word.buffer[1],
     219              66 :                                    word.buffer[2]);
     220                 :       /* Min message size: GRIB1=52, TDLP=59, GRIB2=86. */
     221              22 :       if (*gribLen < 52) {
     222               0 :          errSprintf ("GRIB1 length %ld was < 52?\n", *gribLen);
     223               0 :          return -5;
     224                 :       }
     225               5 :    } else if (word.buffer[3] == 2) {
     226               5 :       *version = 2;
     227                 :       /* Make sure we still have enough file for the rest of section 0. */
     228               5 :       if (fp.DataSourceFread(sect0 + 2, sizeof (sInt4), 2) != 2) {
     229               0 :          errSprintf ("ERROR: Ran out of file reading SECT0\n");
     230               0 :          return -2;
     231                 :       }
     232               5 :       if (sect0[2] != 0) {
     233               0 :          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               0 :                      "bytes.\n");
     237               0 :          return -4;
     238                 :       }
     239                 : #ifdef LITTLE_ENDIAN
     240               5 :       revmemcpy (gribLen, &(sect0[3]), sizeof (sInt4));
     241                 : #else
     242                 :       *gribLen = sect0[3];
     243                 : #endif
     244                 :    } else {
     245               0 :       errSprintf ("ERROR: Not TDLPack, and Grib edition is not 1 or 2\n");
     246               0 :       return -3;
     247                 :    }
     248              27 :    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                 :  */
     286               0 : 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               0 :    cnt = *curMsg + 1;
     298               0 :    buff = NULL;
     299               0 :    buffLen = 0;
     300               0 :    while ((c = fp.DataSourceFgetc()) != EOF) {
     301               0 :       fp.DataSourceUngetc(c);
     302               0 :       if (cnt >= msgNum) {
     303                 :          /* 12/1/2004 version 1.63 forgot to free buff */
     304               0 :          free (buff);
     305               0 :          *curMsg = cnt;
     306               0 :          return 0;
     307                 :       }
     308                 :       /* Read section 0 to find gribLen and wmoLen. */
     309               0 :       if (ReadSECT0 (fp, &buff, &buffLen, GRIB_LIMIT, sect0, &gribLen,
     310                 :                      &version) < 0) {
     311               0 :          preErrSprintf ("Inside FindGRIBMsg\n");
     312               0 :          free (buff);
     313               0 :          return -1;
     314                 :       }
     315                 :       myAssert ((version == 1) || (version == 2) || (version == -1));
     316                 :       /* Continue on to the next grib message. */
     317               0 :       if ((version == 1) || (version == -1)) {
     318               0 :          jump = gribLen - 8;
     319                 :       } else {
     320               0 :          jump = gribLen - 16;
     321                 :       }
     322               0 :       fp.DataSourceFseek(jump, SEEK_CUR);
     323               0 :       *offset = *offset + gribLen + buffLen;
     324               0 :       cnt++;
     325                 :    }
     326               0 :    free (buff);
     327               0 :    *curMsg = cnt - 1;
     328                 :    /* Return -2 since we reached the end of file. This may not be an error
     329                 :     * (multiple file option). */
     330               0 :    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                 :  */
     370               2 : 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               2 :    if ((sectNum == 2) || (sectNum == 3)) {
     378                 :       /* Figure out the size of section 2 and 3. */
     379               2 :       if (*curTot + 5 > gribLen) {
     380               0 :          errSprintf ("ERROR: Ran out of data in Section 2 or 3\n");
     381               0 :          return -1;
     382                 :       }
     383                 :       /* Handle optional section 2. */
     384               2 :       if (c_ipack[*curTot + 4] == 2) {
     385               0 :          MEMCPY_BIG (&sectLen, c_ipack + *curTot, 4);
     386               0 :          *curTot = *curTot + sectLen;
     387               0 :          if (ns[2] < sectLen)
     388               0 :             ns[2] = sectLen;
     389               0 :          if (*curTot + 5 > gribLen) {
     390               0 :             errSprintf ("ERROR: Ran out of data in Section 3\n");
     391               0 :             return -1;
     392                 :          }
     393                 :       }
     394                 :       /* Handle section 3. */
     395               2 :       if (c_ipack[*curTot + 4] != 3) {
     396                 :          errSprintf ("ERROR: Section 3 labeled as %d\n",
     397               0 :                      c_ipack[*curTot + 4]);
     398               0 :          return -2;
     399                 :       }
     400               2 :       MEMCPY_BIG (&sectLen, c_ipack + *curTot, 4);
     401               2 :       if (ns[3] < sectLen)
     402               2 :          ns[3] = sectLen;
     403                 :       /* While we are here, grab the total number of grid points nd2x3. */
     404               2 :       MEMCPY_BIG (&li_temp, c_ipack + *curTot + 6, 4);
     405               2 :       if (*nd2x3 < li_temp)
     406               2 :          *nd2x3 = li_temp;
     407               2 :       *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               2 :    if (*curTot + 5 > gribLen) {
     417               0 :       errSprintf ("ERROR: Ran out of data in Section 4\n");
     418               0 :       return -1;
     419                 :    }
     420               2 :    if (c_ipack[*curTot + 4] != 4) {
     421               0 :       errSprintf ("ERROR: Section 4 labeled as %d\n", c_ipack[*curTot + 4]);
     422               0 :       return -2;
     423                 :    }
     424               2 :    MEMCPY_BIG (&sectLen, c_ipack + *curTot, 4);
     425               2 :    if (ns[4] < sectLen)
     426               2 :       ns[4] = sectLen;
     427               2 :    *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               2 :    if (*curTot + 5 > gribLen) {
     436               0 :       errSprintf ("ERROR: Ran out of data in Section 5\n");
     437               0 :       return -1;
     438                 :    }
     439               2 :    if (c_ipack[*curTot + 4] != 5) {
     440               0 :       errSprintf ("ERROR: Section 5 labeled as %d\n", c_ipack[*curTot + 4]);
     441               0 :       return -2;
     442                 :    }
     443               2 :    MEMCPY_BIG (&sectLen, c_ipack + *curTot, 4);
     444                 :    /* While we are here, grab the packing method. */
     445               2 :    MEMCPY_BIG (table50, c_ipack + *curTot + 9, 2);
     446               2 :    if (ns[5] < sectLen)
     447               2 :       ns[5] = sectLen;
     448               2 :    *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               2 :    if (*curTot + 5 > gribLen) {
     457               0 :       errSprintf ("ERROR: Ran out of data in Section 6\n");
     458               0 :       return -1;
     459                 :    }
     460               2 :    if (c_ipack[*curTot + 4] != 6) {
     461               0 :       errSprintf ("ERROR: Section 6 labeled as %d\n", c_ipack[*curTot + 4]);
     462               0 :       return -2;
     463                 :    }
     464               2 :    MEMCPY_BIG (&sectLen, c_ipack + *curTot, 4);
     465               2 :    if (ns[6] < sectLen)
     466               2 :       ns[6] = sectLen;
     467               2 :    *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               2 :    if (*curTot + 5 > gribLen) {
     476               0 :       errSprintf ("ERROR: Ran out of data in Section 7\n");
     477               0 :       return -1;
     478                 :    }
     479               2 :    if (c_ipack[*curTot + 4] != 7) {
     480               0 :       errSprintf ("ERROR: Section 7 labeled as %d\n", c_ipack[*curTot + 4]);
     481               0 :       return -2;
     482                 :    }
     483               2 :    MEMCPY_BIG (&sectLen, c_ipack + *curTot, 4);
     484               2 :    if (ns[7] < sectLen)
     485               2 :       ns[7] = sectLen;
     486               2 :    *curTot = *curTot + sectLen;
     487                 : /*
     488                 : #ifdef DEBUG
     489                 :    printf ("Section len (7=%ld < %ld)\n", sectLen, ns[7]);
     490                 : #endif
     491                 : */
     492               2 :    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                 :  */
     530               2 : 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               2 :    ns[0] = SECT0LEN_WORD * 4;
     540               2 :    curTot = ns[0];
     541                 : 
     542                 :    /* Figure out the size of section 1. */
     543               2 :    if (curTot + 5 > gribLen) {
     544               0 :       errSprintf ("ERROR: Ran out of data in Section 1\n");
     545               0 :       return -1;
     546                 :    }
     547               2 :    if (c_ipack[curTot + 4] != 1) {
     548               0 :       errSprintf ("ERROR: Section 1 labeled as %d\n", c_ipack[curTot + 4]);
     549               0 :       return -2;
     550                 :    }
     551               2 :    MEMCPY_BIG (&(ns[1]), c_ipack + curTot, 4);
     552               2 :    curTot += ns[1];
     553                 : /*
     554                 : #ifdef DEBUG
     555                 :    printf ("Section len (0=%ld) (1=%ld)\n", ns[0], ns[1]);
     556                 : #endif
     557                 : */
     558               2 :    sectNum = 2;
     559              14 :    for (i = 2; i < 8; i++) {
     560              12 :       ns[i] = -1;
     561                 :    }
     562               2 :    *nd2x3 = -1;
     563               2 :    do {
     564               2 :       if ((ans = FindSectLen2to7 (c_ipack, gribLen, ns, sectNum, &curTot,
     565                 :                                   nd2x3, table50)) != 0) {
     566               0 :          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               2 :       memcpy (&sectLen, c_ipack + curTot, 4);
     572               2 :       if (sectLen == 926365495L) {
     573               2 :          sectNum = 8;
     574                 :       } else {
     575               0 :          sectNum = c_ipack[curTot + 4];
     576               0 :          if ((sectNum < 2) || (sectNum > 7)) {
     577                 :             errSprintf ("ERROR (FindSectLen): Couldn't find the end of the "
     578               0 :                         "message\n");
     579               0 :             errSprintf ("and it doesn't appear to repeat sections.\n");
     580               0 :             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               0 :                         ns[6], ns[7]);
     584               0 :             return -2;
     585                 :          }
     586                 :       }
     587                 :    } while (sectNum != 8);
     588               2 :    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                 :  */
     625               6 : void IS_Init (IS_dataType *is)
     626                 : {
     627                 :    int i;               /* A simple loop counter. */
     628               6 :    is->ns[0] = 16;
     629               6 :    is->ns[1] = 21;
     630               6 :    is->ns[2] = 7;
     631               6 :    is->ns[3] = 96;
     632               6 :    is->ns[4] = 130;     /* 60->130 in case there are some S4 time intervals */
     633               6 :    is->ns[5] = 49;
     634               6 :    is->ns[6] = 6;
     635               6 :    is->ns[7] = 8;
     636              54 :    for (i = 0; i < 8; i++) {
     637              48 :       is->is[i] = (sInt4 *) calloc (is->ns[i], sizeof (sInt4));
     638                 :    }
     639                 :    /* Allocate grid memory. */
     640               6 :    is->nd2x3 = 0;
     641               6 :    is->iain = NULL;
     642               6 :    is->ib = NULL;
     643                 :    /* Allocate section 2 int memory. */
     644               6 :    is->nidat = 0;
     645               6 :    is->idat = NULL;
     646                 :    /* Allocate section 2 float memory. */
     647               6 :    is->nrdat = 0;
     648               6 :    is->rdat = NULL;
     649                 :    /* Allocate storage for ipack. */
     650               6 :    is->ipackLen = 0;
     651               6 :    is->ipack = NULL;
     652               6 : }
     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                 :  */
     679               6 : void IS_Free (IS_dataType *is)
     680                 : {
     681                 :    int i;               /* A simple loop counter. */
     682              54 :    for (i = 0; i < 8; i++) {
     683              48 :       free (is->is[i]);
     684              48 :       is->is[i] = NULL;
     685              48 :       is->ns[i] = 0;
     686                 :    }
     687                 :    /* Free grid memory. */
     688               6 :    free (is->iain);
     689               6 :    is->iain = NULL;
     690               6 :    free (is->ib);
     691               6 :    is->ib = NULL;
     692               6 :    is->nd2x3 = 0;
     693                 :    /* Free section 2 int memory. */
     694               6 :    free (is->idat);
     695               6 :    is->idat = NULL;
     696               6 :    is->nidat = 0;
     697                 :    /* Free section 2 float memory. */
     698               6 :    free (is->rdat);
     699               6 :    is->rdat = NULL;
     700               6 :    is->nrdat = 0;
     701                 :    /* Free storage for ipack. */
     702               6 :    free (is->ipack);
     703               6 :    is->ipack = NULL;
     704               6 :    is->ipackLen = 0;
     705               6 : }
     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
     814               6 : 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                 :                      LatLon *lwlf, LatLon *uprt)
     819                 : {
     820                 :    sInt4 l3264b;        /* Number of bits in a sInt4.  Needed by FORTRAN
     821                 :                          * unpack library to determine if system has a 4
     822                 :                          * byte_ sInt4 or an 8 byte sInt4. */
     823                 :    char *buff;          /* Holds the info between records. */
     824                 :    uInt4 buffLen;       /* Length of info between records. */
     825                 :    sInt4 sect0[SECT0LEN_WORD]; /* Holds the current Section 0. */
     826                 :    uInt4 gribLen;       /* Length of the current GRIB message. */
     827                 :    sInt4 nd5;           /* Size of grib message rounded up to the nearest
     828                 :                          * sInt4. */
     829                 :    char *c_ipack;       /* A char ptr to the message stored in IS->ipack */
     830                 :    sInt4 local_ns[8];   /* Local copy of section lengths. */
     831                 :    sInt4 nd2x3;         /* Total number of grid points. */
     832                 :    short int table50;   /* Type of packing used. (See code table 5.0)
     833                 :                          * (GS5_SIMPLE==0, GS5_CMPLX==2, GS5_CMPLXSEC==3) */
     834                 :    sInt4 nidat;         /* Size of section 2 if it contains integer data. */
     835                 :    sInt4 nrdat;         /* Size of section 2 if it contains float data. */
     836                 :    sInt4 inew;          /* 1 if this is the first grid we are reading. 0 if
     837                 :                          * this is the second or later grid from the same
     838                 :                          * GRIB message. */
     839               6 :    sInt4 iclean = 0;    /* 0 embed the missing values, 1 don't. */
     840                 :    int j;               /* Counter used to find the desired subgrid. */
     841               6 :    sInt4 kfildo = 5;    /* FORTRAN Unit number for diagnostic info. Ignored,
     842                 :                          * unless library is compiled a particular way. */
     843                 :    sInt4 ibitmap;       /* 0 means no bitmap returned, otherwise 1. */
     844                 :    float xmissp;        /* The primary missing value.  If iclean = 0, this
     845                 :                          * value is embeded in grid, otherwise it is the
     846                 :                          * value returned from the GRIB message. */
     847                 :    float xmisss;        /* The secondary missing value.  If iclean = 0, this
     848                 :                          * value is embeded in grid, otherwise it is the
     849                 :                          * value returned from the GRIB message. */
     850                 :    sInt4 jer[UNPK_NUM_ERRORS * 2]; /* Any Error codes along with their *
     851                 :                                     * severity levels generated using the *
     852                 :                                     * unpack GRIB2 library. */
     853               6 :    sInt4 ndjer = UNPK_NUM_ERRORS; /* The number of rows in JER( ). */
     854                 :    sInt4 kjer;          /* The actual number of errors returned in JER. */
     855                 :    size_t i;            /* counter as we loop through jer. */
     856                 :    double unitM, unitB; /* values in y = m x + b used for unit conversion. */
     857                 :    char unitName[15];   /* Holds the string name of the current unit. */
     858                 :    int unitLen;         /* String length of string name of current unit. */
     859                 :    int version;         /* Which version of GRIB is in this message. */
     860                 :    sInt4 cnt;           /* Used to help compact the weather table. */
     861                 :    int x1, y1;          /* The original grid coordinates of the lower left
     862                 :                          * corner of the subgrid. */
     863                 :    int x2, y2;          /* The original grid coordinates of the upper right
     864                 :                          * corner of the subgrid. */
     865                 :    uChar f_subGrid;     /* True if we have a subgrid. */
     866                 :    sInt4 Nx, Ny;        /* original size of the data. */
     867                 : 
     868                 :    /*
     869                 :     * f_endMsg is 1 if in the past we either completed reading a message,
     870                 :     * or we haven't read any messages.  In either case we need to read the
     871                 :     * next message from file.
     872                 :     * If f_endMsg is false, then there is more to read from IS->ipack, so we
     873                 :     * don't want to throw it out, nor have to re-read ipack from disk.
     874                 :     */
     875               6 :    l3264b = sizeof (sInt4) * 8;
     876               6 :    buff = NULL;
     877               6 :    buffLen = 0;
     878               6 :    if (*f_endMsg == 1) {
     879               6 :       if (ReadSECT0 (fp, &buff, &buffLen, -1, sect0, &gribLen, &version) < 0) {
     880               0 :          preErrSprintf ("Inside ReadGrib2Record\n");
     881               0 :          free (buff);
     882               0 :          return -1;
     883                 :       }
     884               6 :       meta->GribVersion = version;
     885               6 :       if (version == 1) {
     886               4 :          if (ReadGrib1Record (fp, f_unit, Grib_Data, grib_DataLen, meta, IS,
     887                 :                               sect0, gribLen, majEarth, minEarth) != 0) {
     888                 :             preErrSprintf ("Problems with ReadGrib1Record called by "
     889               0 :                            "ReadGrib2Record\n");
     890               0 :             free (buff);
     891               0 :             return -1;
     892                 :          }
     893               4 :          *f_endMsg = 1;
     894               4 :          free (buff);
     895               4 :          return 0;
     896               2 :       } else if (version == -1) {
     897               0 :          if (ReadTDLPRecord (fp, Grib_Data, grib_DataLen, meta, IS,
     898                 :                              sect0, gribLen, majEarth, minEarth) != 0) {
     899                 :             preErrSprintf ("Problems with ReadGrib1Record called by "
     900               0 :                            "ReadGrib2Record\n");
     901               0 :             free (buff);
     902               0 :             return -1;
     903                 :          }
     904               0 :          free (buff);
     905               0 :          return 0;
     906                 :       }
     907                 : 
     908                 :       /*
     909                 :        * Make room for entire message, and read it in.
     910                 :        */
     911                 :       /* nd5 needs to be gribLen in (sInt4) units rounded up. */
     912               2 :       nd5 = (gribLen + 3) / 4;
     913               2 :       if (nd5 > IS->ipackLen) {
     914               2 :          IS->ipackLen = nd5;
     915                 :          IS->ipack = (sInt4 *) realloc ((void *) (IS->ipack),
     916               2 :                                         (IS->ipackLen) * sizeof (sInt4));
     917                 :       }
     918               2 :       c_ipack = (char *) IS->ipack;
     919                 :       /* Init last sInt4 to 0, to make sure that the padded bytes are 0. */
     920               2 :       IS->ipack[nd5 - 1] = 0;
     921                 :       /* Init first 4 sInt4 to sect0. */
     922               2 :       memcpy (c_ipack, sect0, SECT0LEN_WORD * 4);
     923                 :       /* Read in the rest of the message. */
     924               2 :       if (fp.DataSourceFread (c_ipack + SECT0LEN_WORD * 4, sizeof (char),
     925               2 :                  (gribLen - SECT0LEN_WORD * 4)) != (gribLen - SECT0LEN_WORD * 4)) {
     926                 :          errSprintf ("GribLen = %ld, SECT0Len_WORD = %d\n", gribLen,
     927               0 :                      SECT0LEN_WORD);
     928               0 :          errSprintf ("Ran out of file\n");
     929               0 :          free (buff);
     930               0 :          return -1;
     931                 :       }
     932                 : 
     933                 :       /*
     934                 :        * Make sure the arrays are large enough for call to unpacker library.
     935                 :        */
     936                 :       /* FindSectLen Does not want (ipack / c_ipack) word swapped, because
     937                 :        * that would make it much more confusing to find bytes in c_ipack. */
     938               2 :       if (FindSectLen (c_ipack, gribLen, local_ns, &nd2x3, &table50) < 0) {
     939               0 :          preErrSprintf ("Inside ReadGrib2Record.. Calling FindSectLen\n");
     940               0 :          free (buff);
     941               0 :          return -2;
     942                 :       }
     943                 : 
     944                 :       /* Make sure all 'is' arrays except ns[7] are MAX (IS.ns[] ,
     945                 :        * local_ns[]). See note 1 for reason to exclude ns[7] from MAX (). */
     946              16 :       for (i = 0; i < 7; i++) {
     947              14 :          if (local_ns[i] > IS->ns[i]) {
     948               0 :             IS->ns[i] = local_ns[i];
     949               0 :             IS->is[i] = (sInt4 *) realloc ((void *) (IS->is[i]),
     950               0 :                                            IS->ns[i] * sizeof (sInt4));
     951                 :          }
     952                 :       }
     953                 : 
     954                 :       /* Allocate room for sect 2. If local_ns[2] = -1 there is no sect 2. */
     955               2 :       if (local_ns[2] == -1) {
     956               2 :          nidat = 10;
     957               2 :          nrdat = 10;
     958                 :       } else {
     959                 :          /*
     960                 :           * See note 2) We have a section 2, so use:
     961                 :           *     MAX (32 * local_ns[2],SECT2_INTSIZE)
     962                 :           * and MAX (32 * local_ns[2],SECT2_FLOATSIZE)
     963                 :           * for size of section 2 unpacked.
     964                 :           */
     965               0 :          nidat = (32 * local_ns[2] < SECT2_INIT_SIZE) ? SECT2_INIT_SIZE :
     966               0 :                32 * local_ns[2];
     967               0 :          nrdat = nidat;
     968                 :       }
     969               2 :       if (nidat > IS->nidat) {
     970               2 :          IS->nidat = nidat;
     971                 :          IS->idat = (sInt4 *) realloc ((void *) IS->idat,
     972               2 :                                        IS->nidat * sizeof (sInt4));
     973                 :       }
     974               2 :       if (nrdat > IS->nrdat) {
     975               2 :          IS->nrdat = nrdat;
     976                 :          IS->rdat = (float *) realloc ((void *) IS->rdat,
     977               2 :                                        IS->nrdat * sizeof (float));
     978                 :       }
     979                 :       /* Make sure we have room for the GRID part of the output. */
     980               2 :       if (nd2x3 > IS->nd2x3) {
     981               2 :          IS->nd2x3 = nd2x3;
     982                 :          IS->iain = (sInt4 *) realloc ((void *) IS->iain,
     983               2 :                                        IS->nd2x3 * sizeof (sInt4));
     984                 :          IS->ib = (sInt4 *) realloc ((void *) IS->ib,
     985               2 :                                      IS->nd2x3 * sizeof (sInt4));
     986                 :       }
     987                 :       /* See note 3) If table50 == 3, unpacker library needs nd5 >= nd2x3. */
     988               2 :       if ((table50 == 3) || (table50 == 0)) {
     989               2 :          if (nd5 < nd2x3) {
     990               2 :             nd5 = nd2x3;
     991               2 :             if (nd5 > IS->ipackLen) {
     992               2 :                IS->ipackLen = nd5;
     993                 :                IS->ipack = (sInt4 *) realloc ((void *) (IS->ipack),
     994               2 :                                               IS->ipackLen * sizeof (sInt4));
     995                 :             }
     996                 :             /* Don't need to do the following, but we do in case code
     997                 :              * changes. */
     998               2 :             c_ipack = (char *) IS->ipack;
     999                 :          }
    1000                 :       }
    1001               2 :       IS->nd5 = nd5;
    1002                 :       /* Unpacker library requires ipack to be MSB. */
    1003                 : /*
    1004                 : #ifdef DEBUG
    1005                 :       if (1==1) {
    1006                 :          FILE *fp = fopen ("test.bin", "wb");
    1007                 :          fwrite (IS->ipack, sizeof (sInt4), IS->nd5, fp);
    1008                 :          fclose (fp);
    1009                 :       }
    1010                 : #endif
    1011                 : */
    1012                 : #ifdef LITTLE_ENDIAN
    1013               2 :       memswp (IS->ipack, sizeof (sInt4), IS->nd5);
    1014                 : #endif
    1015                 :    } else {
    1016               0 :       gribLen = IS->ipack[3];
    1017                 :    }
    1018               2 :    free (buff);
    1019                 : 
    1020                 :    /* Loop through the grib message looking for the subgNum grid.  subgNum
    1021                 :     * goes from 0 to n-1. */
    1022               4 :    for (j = 0; j <= subgNum; j++) {
    1023               2 :       if (j == 0) {
    1024               2 :          inew = 1;
    1025                 :       } else {
    1026               0 :          inew = 0;
    1027                 :       }
    1028                 : 
    1029                 :       /* Note we are getting data back either as a float or an int, but not
    1030                 :        * both, so we don't need to allocated room for both. */
    1031                 :       unpk_grib2 (&kfildo, (float *) (IS->iain), IS->iain, &(IS->nd2x3),
    1032                 :                   IS->idat, &(IS->nidat), IS->rdat, &(IS->nrdat), IS->is[0],
    1033                 :                   &(IS->ns[0]), IS->is[1], &(IS->ns[1]), IS->is[2],
    1034                 :                   &(IS->ns[2]), IS->is[3], &(IS->ns[3]), IS->is[4],
    1035                 :                   &(IS->ns[4]), IS->is[5], &(IS->ns[5]), IS->is[6],
    1036                 :                   &(IS->ns[6]), IS->is[7], &(IS->ns[7]), IS->ib, &ibitmap,
    1037                 :                   IS->ipack, &(IS->nd5), &xmissp, &xmisss, &inew, &iclean,
    1038               2 :                   &l3264b, f_endMsg, jer, &ndjer, &kjer);
    1039                 :       /*
    1040                 :        * Check for error messages...
    1041                 :        *   If we get an error message, print it, and return.
    1042                 :        */
    1043              18 :       for (i = 0; i < (uInt4) kjer; i++) {
    1044              16 :          if (jer[ndjer + i] == 0) {
    1045                 :             /* no error. */
    1046               0 :          } else if (jer[ndjer + i] == 1) {
    1047                 :             /* Warning. */
    1048                 : #ifdef DEBUG
    1049                 :             printf ("Warning: Unpack library warning code (%d %d)\n",
    1050                 :                     jer[i], jer[ndjer + i]);
    1051                 : #endif
    1052                 :          } else {
    1053                 :             /* BAD Error. */
    1054                 :             errSprintf ("ERROR: Unpack library error code (%ld %ld)\n",
    1055               0 :                         jer[i], jer[ndjer + i]);
    1056               0 :             return -3;
    1057                 :          }
    1058                 :       }
    1059                 :    }
    1060                 : 
    1061                 :    /* Parse the meta data out. */
    1062               2 :    if (MetaParse (meta, IS->is[0], IS->ns[0], IS->is[1], IS->ns[1],
    1063                 :                   IS->is[2], IS->ns[2], IS->rdat, IS->nrdat, IS->idat,
    1064                 :                   IS->nidat, IS->is[3], IS->ns[3], IS->is[4], IS->ns[4],
    1065                 :                   IS->is[5], IS->ns[5], gribLen, xmissp, xmisss, simpVer)
    1066                 :        != 0) {
    1067                 : #ifdef DEBUG
    1068                 :       FILE *fp;
    1069                 :       if ((fp = fopen ("dump.is0", "wt")) != NULL) {
    1070                 :          for (i = 0; i < 8; i++) {
    1071                 :             fprintf (fp, "---Section %d---\n", (int) i);
    1072                 :             for (j = 1; j <= IS->ns[i]; j++) {
    1073                 :                fprintf (fp, "IS%d Item %d = %d\n", (int) i, (int) j, IS->is[i][j - 1]);
    1074                 :             }
    1075                 :          }
    1076                 :          fclose (fp);
    1077                 :       }
    1078                 : #endif
    1079               0 :       preErrSprintf ("Inside ReadGrib2Record.. Problems in MetaParse\n");
    1080               0 :       return -4;
    1081                 :    }
    1082                 : 
    1083               2 :    if ((majEarth > 6000) && (majEarth < 7000)) {
    1084               0 :       if ((minEarth > 6000) && (minEarth < 7000)) {
    1085               0 :          meta->gds.f_sphere = 0;
    1086               0 :          meta->gds.majEarth = majEarth;
    1087               0 :          meta->gds.minEarth = minEarth;
    1088                 :       } else {
    1089               0 :          meta->gds.f_sphere = 1;
    1090               0 :          meta->gds.majEarth = majEarth;
    1091               0 :          meta->gds.minEarth = majEarth;
    1092                 :       }
    1093                 :    }
    1094                 : 
    1095                 :    /* Figure out an equation to pass to ParseGrid to convert the units for
    1096                 :     * this grid. */
    1097                 : /*
    1098                 :    if (ComputeUnit (meta->pds2.prodType, meta->pds2.sect4.templat,
    1099                 :                     meta->pds2.sect4.cat, meta->pds2.sect4.subcat, f_unit,
    1100                 :                     &unitM, &unitB, unitName) == 0) {
    1101                 : */
    1102               2 :    if (ComputeUnit (meta->convert, meta->unitName, f_unit, &unitM, &unitB,
    1103                 :                     unitName) == 0) {
    1104               2 :       unitLen = strlen (unitName);
    1105                 :       meta->unitName = (char *) realloc ((void *) (meta->unitName),
    1106               2 :                                          1 + unitLen * sizeof (char));
    1107               2 :       strncpy (meta->unitName, unitName, unitLen);
    1108               2 :       meta->unitName[unitLen] = '\0';
    1109                 :    }
    1110                 : 
    1111                 :    /* compute the subgrid. */
    1112                 :    /*
    1113                 :    if ((lwlf->lat != -100) && (uprt->lat != -100)) {
    1114                 :       Nx = meta->gds.Nx;
    1115                 :       Ny = meta->gds.Ny;
    1116                 :       if (computeSubGrid (lwlf, &x1, &y1, uprt, &x2, &y2, &(meta->gds),
    1117                 :                           &newGds) != 0) {
    1118                 :          preErrSprintf ("ERROR: In compute subgrid.\n");
    1119                 :          return 1;
    1120                 :       }
    1121                 :       // I couldn't decide if I should "permanently" change the GDS or not.
    1122                 :       // when I wrote computeSubGrid.  If next line stays, really should
    1123                 :       // rewrite computeSubGrid.
    1124                 :       memcpy (&(meta->gds), &newGds, sizeof (gdsType));
    1125                 :       f_subGrid = 1;
    1126                 :    } else {
    1127                 :       Nx = meta->gds.Nx;
    1128                 :       Ny = meta->gds.Ny;
    1129                 :       x1 = 1;
    1130                 :       x2 = Nx;
    1131                 :       y1 = 1;
    1132                 :       y2 = Ny;
    1133                 :       f_subGrid = 0;
    1134                 :    }
    1135                 :    */
    1136               2 :    Nx = meta->gds.Nx;
    1137               2 :    Ny = meta->gds.Ny;
    1138               2 :    x1 = 1;
    1139               2 :    x2 = Nx;
    1140               2 :    y1 = 1;
    1141               2 :    y2 = Ny;
    1142               2 :    f_subGrid = 0;
    1143                 : 
    1144                 :    /* Figure out if we need iain or ain, and set it to Grib_Data.  At the
    1145                 :     * same time handle any bitmaps, and compute some statistics. */
    1146               2 :    if ((f_subGrid) && (meta->gds.scan != 64)) {
    1147               0 :       errSprintf ("Can not do a subgrid of non scanmode 64 grid yet.\n");
    1148               0 :       return -3;
    1149                 :    }
    1150                 : 
    1151               2 :    if (strcmp (meta->element, "Wx") != 0) {
    1152                 :       ParseGrid (&(meta->gridAttrib), Grib_Data, grib_DataLen, Nx, Ny,
    1153                 :                  meta->gds.scan, IS->iain, ibitmap, IS->ib, unitM, unitB, 0,
    1154               2 :                  NULL, f_subGrid, x1, y1, x2, y2);
    1155                 :    } else {
    1156                 :       /* Handle weather grid.  ParseGrid looks up the values... If they are
    1157                 :        * "<Invalid>" it sets it to missing (or creates one).  If the table
    1158                 :        * entry is used it sets f_valid to 2. */
    1159                 :       ParseGrid (&(meta->gridAttrib), Grib_Data, grib_DataLen, Nx, Ny,
    1160                 :                  meta->gds.scan, IS->iain, ibitmap, IS->ib, unitM, unitB, 1,
    1161                 :                  (sect2_WxType *) &(meta->pds2.sect2.wx), f_subGrid, x1, y1,
    1162               0 :                  x2, y2);
    1163                 : 
    1164                 :       /* compact the table to only those which are actually used. */
    1165               0 :       cnt = 0;
    1166               0 :       for (i = 0; i < meta->pds2.sect2.wx.dataLen; i++) {
    1167               0 :          if (meta->pds2.sect2.wx.ugly[i].f_valid == 2) {
    1168               0 :             meta->pds2.sect2.wx.ugly[i].validIndex = cnt;
    1169               0 :             cnt++;
    1170               0 :          } else if (meta->pds2.sect2.wx.ugly[i].f_valid == 3) {
    1171               0 :             meta->pds2.sect2.wx.ugly[i].f_valid = 0;
    1172               0 :             meta->pds2.sect2.wx.ugly[i].validIndex = cnt;
    1173               0 :             cnt++;
    1174                 :          } else {
    1175               0 :             meta->pds2.sect2.wx.ugly[i].validIndex = -1;
    1176                 :          }
    1177                 :       }
    1178                 :    }
    1179                 : 
    1180                 :    /* Figure out some other non-section oriented meta data. */
    1181                 : /*   strftime (meta->refTime, 20, "%Y%m%d%H%M",
    1182                 :              gmtime (&(meta->pds2.refTime)));
    1183                 : */
    1184               2 :    Clock_Print (meta->refTime, 20, meta->pds2.refTime, "%Y%m%d%H%M", 0);
    1185                 : /*
    1186                 :    strftime (meta->validTime, 20, "%Y%m%d%H%M",
    1187                 :              gmtime (&(meta->pds2.sect4.validTime)));
    1188                 : */
    1189                 :    Clock_Print (meta->validTime, 20, meta->pds2.sect4.validTime,
    1190               2 :                 "%Y%m%d%H%M", 0);
    1191                 : 
    1192               2 :    meta->deltTime = (sInt4) (meta->pds2.sect4.validTime - meta->pds2.refTime);
    1193                 : 
    1194               2 :    return 0;
    1195                 : }

Generated by: LCOV version 1.7