LCOV - code coverage report
Current view: directory - frmts/grib/degrib18/degrib - inventory.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 421 148 35.2 %
Date: 2010-01-09 Functions: 8 6 75.0 %

       1                 : /*****************************************************************************
       2                 :  * inventory.c
       3                 :  *
       4                 :  * DESCRIPTION
       5                 :  *    This file contains the code needed to do a quick inventory of the GRIB2
       6                 :  * file.  The intent is to enable one to figure out which message in a GRIB
       7                 :  * file one is after without needing to call 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 "clock.h"
      22                 : #include "memendian.h"
      23                 : #include "fileendian.h"
      24                 : #include "degrib2.h"
      25                 : #include "degrib1.h"
      26                 : #include "tdlpack.h"
      27                 : #include "myerror.h"
      28                 : #include "myutil.h"
      29                 : #include "myassert.h"
      30                 : #include "inventory.h"
      31                 : #include "metaname.h"
      32                 : #include "filedatasource.h"
      33                 : 
      34                 : #define SECT0LEN_BYTE 16
      35                 : 
      36                 : typedef union {
      37                 :    sInt4 li;
      38                 :    char buffer[4];
      39                 : } wordType;
      40                 : 
      41                 : /*****************************************************************************
      42                 :  * GRIB2InventoryFree() -- Review 12/2002
      43                 :  *
      44                 :  * Arthur Taylor / MDL
      45                 :  *
      46                 :  * PURPOSE
      47                 :  *   Free's any memory that was allocated for the inventory of a single grib
      48                 :  * message
      49                 :  *
      50                 :  * ARGUMENTS
      51                 :  * inv = Pointer to the inventory of a single grib message. (Input/Output)
      52                 :  *
      53                 :  * FILES/DATABASES: None
      54                 :  *
      55                 :  * RETURNS: void
      56                 :  *
      57                 :  * HISTORY
      58                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
      59                 :  *  12/2002 (TK,AC,TB,&MS): Code Review.
      60                 :  *   7/2003 AAT: memwatch detected unfreed inv->unitName
      61                 :  *
      62                 :  * NOTES
      63                 :  *****************************************************************************
      64                 :  */
      65              18 : void GRIB2InventoryFree (inventoryType *inv)
      66                 : {
      67              18 :    free (inv->element);
      68              18 :    inv->element = NULL;
      69              18 :    free (inv->comment);
      70              18 :    inv->comment = NULL;
      71              18 :    free (inv->unitName);
      72              18 :    inv->unitName = NULL;
      73              18 :    free (inv->shortFstLevel);
      74              18 :    inv->shortFstLevel = NULL;
      75              18 :    free (inv->longFstLevel);
      76              18 :    inv->longFstLevel = NULL;
      77              18 : }
      78                 : 
      79                 : /*****************************************************************************
      80                 :  * GRIB2InventoryPrint() -- Review 12/2002
      81                 :  *
      82                 :  * Arthur Taylor / MDL
      83                 :  *
      84                 :  * PURPOSE
      85                 :  *   Prints to standard out, an inventory of the file, assuming one has an
      86                 :  * array of invenories of single grib messages.
      87                 :  *
      88                 :  * ARGUMENTS
      89                 :  *    Inv = Pointer to an Array of inventories to print. (Input)
      90                 :  * LenInv = Length of the Array Inv (Input)
      91                 :  *
      92                 :  * FILES/DATABASES: None
      93                 :  *
      94                 :  * RETURNS: void
      95                 :  *
      96                 :  * HISTORY
      97                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
      98                 :  *  12/2002 (TK,AC,TB,&MS): Code Review.
      99                 :  *   1/2004 AAT: Added short form of First level to print out.
     100                 :  *   3/2004 AAT: Switched from "#, Byte, ..." to "MsgNum, Byte, ..."
     101                 :  *
     102                 :  * NOTES
     103                 :  *****************************************************************************
     104                 :  */
     105               0 : void GRIB2InventoryPrint (inventoryType *Inv, uInt4 LenInv)
     106                 : {
     107                 :    uInt4 i;             /* Counter of which inventory we are printing. */
     108                 :    double delta;        /* Difference between valid and reference time. */
     109                 :    char refTime[25];    /* Used to store the formatted reference time. */
     110                 :    char validTime[25];  /* Used to store the formatted valid time. */
     111                 : 
     112                 :    printf ("MsgNum, Byte, GRIB-Version, elem, level, reference(UTC),"
     113               0 :            " valid(UTC), Proj(hr)\n");
     114               0 :    fflush (stdout);
     115               0 :    for (i = 0; i < LenInv; i++) {
     116                 : /*      strftime (refTime, 25, "%m/%d/%Y %H:%M", gmtime (&(Inv[i].refTime)));*/
     117               0 :       Clock_Print (refTime, 25, Inv[i].refTime, "%m/%d/%Y %H:%M", 0);
     118                 : /*      strftime (validTime, 25, "%m/%d/%Y %H:%M",
     119                 :                 gmtime (&(Inv[i].validTime)));*/
     120               0 :       Clock_Print (validTime, 25, Inv[i].validTime, "%m/%d/%Y %H:%M", 0);
     121               0 :       delta = (Inv[i].validTime - Inv[i].refTime) / 3600.;
     122               0 :       delta = myRound (delta, 2);
     123               0 :       if (Inv[i].comment == NULL) {
     124                 :          printf ("%d.%d, %d, %d, %s, %s, %s, %s, %.2f\n",
     125               0 :                  Inv[i].msgNum, Inv[i].subgNum, Inv[i].start,
     126               0 :                  Inv[i].GribVersion, Inv[i].element, Inv[i].shortFstLevel,
     127               0 :                  refTime, validTime, delta);
     128               0 :          fflush (stdout);
     129                 :       } else {
     130                 :          printf ("%d.%d, %d, %d, %s=\"%s\", %s, %s, %s, %.2f\n",
     131               0 :                  Inv[i].msgNum, Inv[i].subgNum, Inv[i].start,
     132               0 :                  Inv[i].GribVersion, Inv[i].element, Inv[i].comment,
     133               0 :                  Inv[i].shortFstLevel, refTime, validTime, delta);
     134               0 :          fflush (stdout);
     135                 :       }
     136                 :    }
     137               0 : }
     138                 : 
     139                 : /*****************************************************************************
     140                 :  * InventoryParseTime() -- Review 12/2002
     141                 :  *
     142                 :  * Arthur Taylor / MDL
     143                 :  *
     144                 :  * PURPOSE
     145                 :  *    To parse the time data from a grib2 char array to a time_t in UTC
     146                 :  * seconds from the epoch.  This is very similar to metaparse.c:ParseTime
     147                 :  * except using char * instead of sInt4
     148                 :  *
     149                 :  * ARGUMENTS
     150                 :  *      is = The char array to read the time info from. (Input)
     151                 :  * AnsTime = The time_t value to fill with the resulting time. (Output)
     152                 :  *
     153                 :  * FILES/DATABASES: None
     154                 :  *
     155                 :  * RETURNS: void
     156                 :  *
     157                 :  * HISTORY
     158                 :  *  11/2002 Arthur Taylor (MDL/RSIS): Created.
     159                 :  *  12/2002 (TK,AC,TB,&MS): Code Review.
     160                 :  *
     161                 :  * NOTES
     162                 :  * 1) Couldn't use the default time_zone variable (concern over portability
     163                 :  *    issues), so we print the hours, and compare them to the hours we had
     164                 :  *    intended.  Then subtract the difference from the AnsTime.
     165                 :  * 2) Similar to metaparse.c:ParseTime except using char * instead of sInt4
     166                 :  *****************************************************************************
     167                 :  */
     168               4 : static int InventoryParseTime (char *is, double *AnsTime)
     169                 : {
     170                 :    /* struct tm time; *//* A temporary variable to put the time info into. */
     171                 :    /* char buffer[10]; *//* Used when printing the AnsTime's Hr. */
     172                 :    /* int timeZone; *//* The adjustment in Hr needed to get the right UTC * time. */
     173                 :    short int si_temp;   /* Temporarily stores the year as a short int to fix
     174                 :                          * possible endian problems. */
     175                 : 
     176                 : /*   memset (&time, 0, sizeof (struct tm));*/
     177               4 :    MEMCPY_BIG (&si_temp, is + 0, sizeof (short int));
     178               4 :    if ((si_temp < 1900) || (si_temp > 2100)) {
     179               0 :       return -1;
     180                 :    }
     181              12 :    if ((is[2] > 12) || (is[3] == 0) || (is[3] > 31) || (is[4] > 24) ||
     182               8 :        (is[5] > 60) || (is[6] > 61)) {
     183               0 :       return -1;
     184                 :    }
     185               4 :    Clock_ScanDate (AnsTime, si_temp, is[2], is[3]);
     186               4 :    *AnsTime += is[4] * 3600. + is[5] * 60. + is[6];
     187                 : /*
     188                 :    time.tm_year = si_temp - 1900;
     189                 :    time.tm_mon = is[2] - 1;
     190                 :    time.tm_mday = is[3];
     191                 :    time.tm_hour = is[4];
     192                 :    time.tm_min = is[5];
     193                 :    time.tm_sec = is[6];
     194                 :    *AnsTime = mktime (&time) - (Clock_GetTimeZone () * 3600);
     195                 : */
     196                 :    /* Cheap method of getting global time_zone variable. */
     197                 : /*
     198                 :    strftime (buffer, 10, "%H", gmtime (AnsTime));
     199                 :    timeZone = atoi (buffer) - is[4];
     200                 :    if (timeZone < 0) {
     201                 :       timeZone += 24;
     202                 :    }
     203                 :    *AnsTime = *AnsTime - (timeZone * 3600);
     204                 : */
     205               4 :    return 0;
     206                 : }
     207                 : 
     208                 : /*****************************************************************************
     209                 :  * GRIB2SectToBuffer() -- Review 12/2002
     210                 :  *
     211                 :  * Arthur Taylor / MDL
     212                 :  *
     213                 :  * PURPOSE
     214                 :  *    To read in a GRIB2 section into a buffer.  Reallocates space for the
     215                 :  * section if buffLen < secLen.  Reads in secLen and checks that the section
     216                 :  * is valid, and the file is large enough to hold the entire section.
     217                 :  *
     218                 :  * ARGUMENTS
     219                 :  *      fp = Opened file pointing to the section in question. (Input/Output)
     220                 :  * gribLen = The total length of the grib message. (Input)
     221                 :  *    sect = Which section we think we are reading.
     222                 :  *           If it is -1, then set it to the section the file says we are
     223                 :  *           reading (useful for optional sect 2)) (Input/Output).
     224                 :  *  secLen = The length of this section (Output)
     225                 :  * buffLen = Allocated length of buff (Input/Output)
     226                 :  *    buff = Stores the section (Output)
     227                 :  *
     228                 :  * FILES/DATABASES:
     229                 :  *    An already opened GRIB2 file pointer, already at section in question.
     230                 :  *
     231                 :  * RETURNS: int (could use errSprintf())
     232                 :  *  0 = Ok.
     233                 :  * -1 = Ran out of file.
     234                 :  * -2 = Section was miss-labeled.
     235                 :  *
     236                 :  * HISTORY
     237                 :  *  11/2002 Arthur Taylor (MDL/RSIS): Created.
     238                 :  *  12/2002 (TK,AC,TB,&MS): Code Review.
     239                 :  *   8/2003 AAT: Removed dependence on curTot
     240                 :  *
     241                 :  * NOTES
     242                 :  *   May want to put this in degrib2.c
     243                 :  *****************************************************************************
     244                 :  */
     245               4 : static int GRIB2SectToBuffer (DataSource &fp, uInt4 gribLen, sChar *sect,
     246                 :                               uInt4 *secLen, uInt4 *buffLen, char **buff)
     247                 : {
     248               4 :    char *buffer = *buff; /* Local ptr to buff to reduce ptr confusion. */
     249                 : 
     250               4 :    if (FREAD_BIG (secLen, sizeof (sInt4), 1, fp) != 1) {
     251               0 :       if (*sect != -1) {
     252               0 :          errSprintf ("ERROR: Ran out of file in Section %d\n", *sect);
     253                 :       } else {
     254               0 :          errSprintf ("ERROR: Ran out of file in GRIB2SectToBuffer\n");
     255                 :       }
     256               0 :       return -1;
     257                 :    }
     258               4 :    if (*buffLen < *secLen) {
     259               2 :       *buffLen = *secLen;
     260               2 :       *buff = (char *) realloc ((void *) *buff, *buffLen * sizeof (char));
     261               2 :       buffer = *buff;
     262                 :    }
     263                 : 
     264               4 :    if (fp.DataSourceFread (buffer, sizeof (char), *secLen - sizeof (sInt4)) !=
     265                 :        *secLen - sizeof (sInt4)) {
     266               0 :       if (*sect != -1) {
     267               0 :          errSprintf ("ERROR: Ran out of file in Section %d\n", *sect);
     268                 :       } else {
     269               0 :          errSprintf ("ERROR: Ran out of file in GRIB2SectToBuffer\n");
     270                 :       }
     271               0 :       return -1;
     272                 :    }
     273               4 :    if (*sect == -1) {
     274               0 :       *sect = buffer[5 - 5];
     275               4 :    } else if (buffer[5 - 5] != *sect) {
     276               0 :       errSprintf ("ERROR: Section %d misslabeled\n", *sect);
     277               0 :       return -2;
     278                 :    }
     279               4 :    return 0;
     280                 : }
     281                 : 
     282                 : /*****************************************************************************
     283                 :  * GRIB2SectJump() --
     284                 :  *
     285                 :  * Arthur Taylor / MDL
     286                 :  *
     287                 :  * PURPOSE
     288                 :  *    To jump past a GRIB2 section.  Reads in secLen and checks that the
     289                 :  * section is valid.
     290                 :  *
     291                 :  * ARGUMENTS
     292                 :  *      fp = Opened file pointing to the section in question. (Input/Output)
     293                 :  * gribLen = The total length of the grib message. (Input)
     294                 :  *    sect = Which section we think we are reading.
     295                 :  *           If it is -1, then set it to the section the file says we are
     296                 :  *           reading (useful for optional sect 2)) (Input/Output).
     297                 :  *  secLen = The length of this section (Output)
     298                 :  *
     299                 :  * FILES/DATABASES:
     300                 :  *    An already opened GRIB2 file pointer, already at section in question.
     301                 :  *
     302                 :  * RETURNS: int (could use errSprintf())
     303                 :  *  0 = Ok.
     304                 :  * -1 = Ran out of file.
     305                 :  * -2 = Section was miss-labeled.
     306                 :  *
     307                 :  * HISTORY
     308                 :  *   3/2003 Arthur Taylor (MDL/RSIS): Created.
     309                 :  *   8/2003 AAT: Removed dependence on curTot, which was used to compute if
     310                 :  *          the file should be large enough for the fseek, but didn't check
     311                 :  *          if it actually was.
     312                 :  *
     313                 :  * NOTES
     314                 :  *   May want to put this in degrib2.c
     315                 :  *****************************************************************************
     316                 :  */
     317               8 : static int GRIB2SectJump (DataSource &fp, sInt4 gribLen, sChar *sect, uInt4 *secLen)
     318                 : {
     319                 :    char sectNum;        /* Validates that we are on the correct section. */
     320                 :    int c;               /* Check that the fseek is still inside the file. */
     321                 : 
     322               8 :    if (FREAD_BIG (secLen, sizeof (sInt4), 1, fp) != 1) {
     323               0 :       if (*sect != -1) {
     324               0 :          errSprintf ("ERROR: Ran out of file in Section %d\n", *sect);
     325                 :       } else {
     326               0 :          errSprintf ("ERROR: Ran out of file in GRIB2SectSkip\n");
     327                 :       }
     328               0 :       return -1;
     329                 :    }
     330               8 :    if (fp.DataSourceFread (&sectNum, sizeof (char), 1) != 1) {
     331               0 :       if (*sect != -1) {
     332               0 :          errSprintf ("ERROR: Ran out of file in Section %d\n", *sect);
     333                 :       } else {
     334               0 :          errSprintf ("ERROR: Ran out of file in GRIB2SectSkip\n");
     335                 :       }
     336               0 :       return -1;
     337                 :    }
     338               8 :    if (*sect == -1) {
     339               2 :       *sect = sectNum;
     340               6 :    } else if (sectNum != *sect) {
     341               0 :       errSprintf ("ERROR: Section %d misslabeled\n", *sect);
     342               0 :       return -2;
     343                 :    }
     344                 :    /* Since fseek does not give an error if we jump outside the file, we test 
     345                 :     * it by using fgetc / ungetc. */
     346               8 :    fp.DataSourceFseek (*secLen - 5, SEEK_CUR);
     347               8 :    if ((c = fp.DataSourceFgetc()) == EOF) {
     348               0 :       errSprintf ("ERROR: Ran out of file in Section %d\n", *sect);
     349               0 :       return -1;
     350                 :    } else {
     351               8 :      fp.DataSourceUngetc(c);
     352                 :    }
     353               8 :    return 0;
     354                 : }
     355                 : 
     356                 : /*****************************************************************************
     357                 :  * GRIB2Inventory2to7() --
     358                 :  *
     359                 :  * Arthur Taylor / MDL
     360                 :  *
     361                 :  * PURPOSE
     362                 :  *   Inventories sections 3 to 7, filling out the inv record with the data in
     363                 :  * section 4.  (Note: No Call to FORTRAN routines here).
     364                 :  *
     365                 :  * ARGUMENTS
     366                 :  *   sectNum = Which section we are currently reading. (Input)
     367                 :  *        fp = An opened file pointer to the file to the inventory of (In/Out)
     368                 :  *   gribLen = The total length of the grib message. (Input)
     369                 :  *   buffLen = length of buffer. (Input)
     370                 :  *    buffer = Holds a given section. (Input)
     371                 :  *       inv = The current inventory record to fill out. (Output)
     372                 :  *  prodType = The GRIB2 type of product: 0 is meteo product, 1 is hydro,
     373                 :  *             2 is land, 3 is space, 10 is oceanographic. (Input)
     374                 :  *    center = Who produced it (Input)
     375                 :  * subcenter = A sub group of center that actually produced it (Input)
     376                 :  *
     377                 :  * FILES/DATABASES:
     378                 :  *
     379                 :  * RETURNS: int (could use errSprintf())
     380                 :  *  0 = "Ok"
     381                 :  * -5 = Problems Reading in section 2 or 3
     382                 :  * -6 = Problems Reading in section 3
     383                 :  * -7 = Problems Reading in section 4
     384                 :  * -8 = Problems Parsing section 4.
     385                 :  * -9 = Problems Reading in section 5
     386                 :  * -10 = Problems Reading in section 6
     387                 :  * -11 = Problems Reading in section 7
     388                 :  *
     389                 :  * HISTORY
     390                 :  *   3/2003 Arthur Taylor (MDL/RSIS): Created.
     391                 :  *   4/2003 AAT: Modified to not have prodType, cat, subcat, templat in
     392                 :  *          inventoryType structure.
     393                 :  *   8/2003 AAT: curTot no longer serves a purpose.
     394                 :  *   1/2004 AAT: Added center/subcenter.
     395                 :  *
     396                 :  * NOTES
     397                 :  *****************************************************************************
     398                 :  */
     399               2 : static int GRIB2Inventory2to7 (sChar sectNum, DataSource &fp, sInt4 gribLen,
     400                 :                                uInt4 *buffLen, char **buffer,
     401                 :                                inventoryType *inv, uChar prodType,
     402                 :                                unsigned short int center,
     403                 :                                unsigned short int subcenter)
     404                 : {
     405                 :    uInt4 secLen;        /* The length of the current section. */
     406                 :    sInt4 foreTime;      /* forecast time (NDFD treats as "projection") */
     407                 :    uChar foreTimeUnit;  /* The time unit of the "forecast time". */
     408                 :    /* char *element; *//* Holds the name of the current variable. */
     409                 :    /* char *comment; *//* Holds more comments about current variable. */
     410                 :    /* char *unitName; *//* Holds the name of the unit [K] [%] .. etc */
     411                 :    int convert;         /* Enum type of unit conversions (metaname.c),
     412                 :                          * Conversion method for this variable's unit. */
     413                 :    uChar cat;           /* General category of Meteo Product. */
     414                 :    unsigned short int templat; /* The section 4 template number. */
     415                 :    uChar subcat;        /* Specific subcategory of Product. */
     416                 :    uChar fstSurfType;   /* Type of the first fixed surface. */
     417                 :    double fstSurfValue; /* Value of first fixed surface. */
     418                 :    sInt4 value;         /* The scaled value from GRIB2 file. */
     419                 :    sChar factor;        /* The scaled factor from GRIB2 file */
     420                 :    sChar scale;         /* Surface scale as opposed to probility factor. */
     421                 :    uChar sndSurfType;   /* Type of the second fixed surface. */
     422                 :    double sndSurfValue; /* Value of second fixed surface. */
     423                 :    sChar f_sndValue;    /* flag if SndValue is valid. */
     424                 :    uChar timeRangeUnit;
     425                 :    sInt4 lenTime;       /* Used by parseTime to tell difference betweeen 8hr
     426                 :                          * average and 1hr average ozone. */
     427                 :    uChar genID;         /* The Generating process ID (used for GFS MOS) */
     428                 :    uChar probType;      /* The probability type */
     429                 :    double lowerProb;    /* The lower limit on probability forecast if
     430                 :                          * template 4.5 or 4.9 */
     431                 :    double upperProb;    /* The upper limit on probability forecast if
     432                 :                          * template 4.5 or 4.9 */
     433                 :    uChar timeIncrType;
     434               2 :    sChar percentile = 0;
     435                 : 
     436               2 :    if ((sectNum == 2) || (sectNum == 3)) {
     437                 :       /* Jump past section (2 or 3). */
     438               2 :       sectNum = -1;
     439               2 :       if (GRIB2SectJump (fp, gribLen, &sectNum, &secLen) != 0) {
     440               0 :          errSprintf ("ERROR: Problems Jumping past section 2 || 3\n");
     441               0 :          return -6;
     442                 :       }
     443               2 :       if ((sectNum != 2) && (sectNum != 3)) {
     444               0 :          errSprintf ("ERROR: Section 2 or 3 misslabeled\n");
     445               0 :          return -5;
     446               2 :       } else if (sectNum == 2) {
     447                 :          /* Jump past section 3. */
     448               0 :          sectNum = 3;
     449               0 :          if (GRIB2SectJump (fp, gribLen, &sectNum, &secLen) != 0) {
     450               0 :             errSprintf ("ERROR: Problems Jumping past section 3\n");
     451               0 :             return -6;
     452                 :          }
     453                 :       }
     454                 :    }
     455                 :    /* Read section 4 into buffer. */
     456               2 :    sectNum = 4;
     457               2 :    if (GRIB2SectToBuffer (fp, gribLen, &sectNum, &secLen, buffLen,
     458                 :                           buffer) != 0) {
     459               0 :       errSprintf ("ERROR: Problems with section 4\n");
     460               0 :       return -7;
     461                 :    }
     462                 : /*
     463                 : enum { GS4_ANALYSIS, GS4_ENSEMBLE, GS4_DERIVED, GS4_PROBABIL_PNT = 5,
     464                 :    GS4_STATISTIC = 8, GS4_PROBABIL_TIME = 9, GS4_PERCENTILE = 10,
     465                 :    GS4_RADAR = 20, GS4_SATELLITE = 30
     466                 : };
     467                 : */
     468                 :    /* Parse the interesting data out of sect 4. */
     469               2 :    MEMCPY_BIG (&templat, *buffer + 8 - 5, sizeof (short int));
     470               2 :    if ((templat != GS4_ANALYSIS) && (templat != GS4_ENSEMBLE)
     471                 :        && (templat != GS4_DERIVED)
     472                 :        && (templat != GS4_PROBABIL_PNT) && (templat != GS4_STATISTIC)
     473                 :        && (templat != GS4_PROBABIL_TIME) && (templat != GS4_PERCENTILE)
     474                 :        && (templat != GS4_ENSEMBLE_STAT)
     475                 :        && (templat != GS4_RADAR) && (templat != GS4_SATELLITE)
     476                 :        && (templat != GS4_DERIVED_INTERVAL)) {
     477                 :       errSprintf ("This was only designed for templates 0, 1, 2, 5, 8, 9, "
     478               0 :                   "10, 11, 12, 20, 30\n");
     479               0 :       return -8;
     480                 :    }
     481               2 :    cat = (*buffer)[10 - 5];
     482               2 :    subcat = (*buffer)[11 - 5];
     483               2 :    genID = 0;
     484               2 :    probType = 0;
     485               2 :    lowerProb = 0;
     486               2 :    upperProb = 0;
     487               2 :    if ((templat == GS4_RADAR) || (templat == GS4_SATELLITE) ||
     488                 :        (templat == 254)) {
     489               0 :       inv->foreSec = 0;
     490               0 :       inv->validTime = inv->refTime;
     491               0 :       timeIncrType = 255;
     492               0 :       timeRangeUnit = 255;
     493               0 :       lenTime = 0;
     494                 :    } else {
     495               2 :       genID = (*buffer)[14 - 5];
     496                 :       /* Compute forecast time. */
     497               2 :       foreTimeUnit = (*buffer)[18 - 5];
     498               2 :       MEMCPY_BIG (&foreTime, *buffer + 19 - 5, sizeof (sInt4));
     499               2 :       if (ParseSect4Time2sec (foreTime, foreTimeUnit, &(inv->foreSec)) != 0) {
     500               0 :          errSprintf ("unable to convert TimeUnit: %d \n", foreTimeUnit);
     501               0 :          return -8;
     502                 :       }
     503                 :       /* Compute valid time. */
     504               2 :       inv->validTime = inv->refTime + inv->foreSec;
     505               2 :       timeIncrType = 255;
     506               2 :       timeRangeUnit = 1;
     507               2 :       lenTime = (sInt4) (inv->foreSec / 3600);
     508               2 :       switch (templat) {
     509                 :          case GS4_PROBABIL_PNT: /* 4.5 */
     510               0 :             probType = (*buffer)[37 - 5];
     511               0 :             factor = (sChar) (*buffer)[38 - 5];
     512               0 :             MEMCPY_BIG (&value, *buffer + 39 - 5, sizeof (sInt4));
     513               0 :             lowerProb = value * pow (10.0, -1 * factor);
     514               0 :             factor = (sChar) (*buffer)[43 - 5];
     515               0 :             MEMCPY_BIG (&value, *buffer + 44 - 5, sizeof (sInt4));
     516               0 :             upperProb = value * pow (10.0, -1 * factor);
     517               0 :             break;
     518                 :          case GS4_DERIVED_INTERVAL: /* 4.12 */
     519               0 :             if (InventoryParseTime (*buffer + 37 - 5, &(inv->validTime)) != 0) {
     520               0 :                printf ("Warning: Investigate Template 4.12 bytes 37-43\n");
     521               0 :                inv->validTime = inv->refTime + inv->foreSec;
     522                 :             }
     523               0 :             timeIncrType = (*buffer)[50 - 5];
     524               0 :             timeRangeUnit = (*buffer)[51 - 5];
     525               0 :             MEMCPY_BIG (&lenTime, *buffer + 52 - 5, sizeof (sInt4));
     526                 : /* If lenTime == missing (2^32 -1) we might do something, but not with 255.*/
     527                 : /*
     528                 :             if (lenTime == 255) {
     529                 :                lenTime = (inv->validTime -
     530                 :                           (inv->refTime + inv->foreSec)) / 3600;
     531                 :             }
     532                 : */
     533               0 :             break;
     534                 :          case GS4_PERCENTILE: /* 4.10 */
     535               0 :             percentile = (*buffer)[35 - 5];
     536               0 :             if (InventoryParseTime (*buffer + 36 - 5, &(inv->validTime)) != 0) {
     537               0 :                printf ("Warning: Investigate Template 4.10 bytes 36-42\n");
     538               0 :                inv->validTime = inv->refTime + inv->foreSec;
     539                 :             }
     540               0 :             timeIncrType = (*buffer)[49 - 5];
     541               0 :             timeRangeUnit = (*buffer)[50 - 5];
     542               0 :             MEMCPY_BIG (&lenTime, *buffer + 51 - 5, sizeof (sInt4));
     543                 : /* If lenTime == missing (2^32 -1) we might do something, but not with 255.*/
     544                 : /*
     545                 :             if (lenTime == 255) {
     546                 :                lenTime = (inv->validTime -
     547                 :                           (inv->refTime + inv->foreSec)) / 3600;
     548                 :             }
     549                 : */
     550               0 :             break;
     551                 :          case GS4_STATISTIC: /* 4.8 */
     552               2 :             if (InventoryParseTime (*buffer + 35 - 5, &(inv->validTime)) != 0) {
     553               0 :                printf ("Warning: Investigate Template 4.8 bytes 35-41\n");
     554               0 :                inv->validTime = inv->refTime + inv->foreSec;
     555                 :             }
     556               2 :             timeIncrType = (*buffer)[48 - 5];
     557               2 :             timeRangeUnit = (*buffer)[49 - 5];
     558               2 :             MEMCPY_BIG (&lenTime, *buffer + 50 - 5, sizeof (sInt4));
     559                 : /* If lenTime == missing (2^32 -1) we might do something, but not with 255.*/
     560                 : /*
     561                 :             if (lenTime == 255) {
     562                 :                lenTime = (inv->validTime -
     563                 :                           (inv->refTime + inv->foreSec)) / 3600;
     564                 :             }
     565                 : */
     566               2 :             break;
     567                 :          case GS4_ENSEMBLE_STAT: /* 4.11 */
     568               0 :             if (InventoryParseTime (*buffer + 38 - 5, &(inv->validTime)) != 0) {
     569               0 :                printf ("Warning: Investigate Template 4.11 bytes 38-44\n");
     570               0 :                inv->validTime = inv->refTime + inv->foreSec;
     571                 :             }
     572               0 :             timeIncrType = (*buffer)[51 - 5];
     573               0 :             timeRangeUnit = (*buffer)[52 - 5];
     574               0 :             MEMCPY_BIG (&lenTime, *buffer + 53 - 5, sizeof (sInt4));
     575                 : /* If lenTime == missing (2^32 -1) we might do something, but not with 255.*/
     576                 : /*
     577                 :             if (lenTime == 255) {
     578                 :                lenTime = (inv->validTime -
     579                 :                           (inv->refTime + inv->foreSec)) / 3600;
     580                 :             }
     581                 : */
     582               0 :             break;
     583                 :          case GS4_PROBABIL_TIME: /* 4.9 */
     584               0 :             probType = (*buffer)[37 - 5];
     585               0 :             if ((uChar) (*buffer)[38 - 5] > 128) {
     586               0 :                factor = 128 - (uChar) (*buffer)[38 - 5];
     587                 :             } else {
     588               0 :                factor = (*buffer)[38 - 5];
     589                 :             }
     590               0 :             MEMCPY_BIG (&value, *buffer + 39 - 5, sizeof (sInt4));
     591               0 :             lowerProb = value * pow (10.0, -1 * factor);
     592                 : 
     593               0 :             if ((uChar) (*buffer)[43 - 5] > 128) {
     594               0 :                factor = 128 - (uChar) (*buffer)[43 - 5];
     595                 :             } else {
     596               0 :                factor = (*buffer)[43 - 5];
     597                 :             }
     598               0 :             MEMCPY_BIG (&value, *buffer + 44 - 5, sizeof (sInt4));
     599               0 :             upperProb = value * pow (10.0, -1 * factor);
     600                 : 
     601               0 :             if (InventoryParseTime (*buffer + 48 - 5, &(inv->validTime)) != 0) {
     602               0 :                printf ("Warning: Investigate Template 4.9 bytes 48-54\n");
     603               0 :                inv->validTime = inv->refTime + inv->foreSec;
     604                 :             }
     605               0 :             timeIncrType = (*buffer)[61 - 5];
     606               0 :             timeRangeUnit = (*buffer)[62 - 5];
     607               0 :             MEMCPY_BIG (&lenTime, *buffer + 63 - 5, sizeof (sInt4));
     608                 : /* If lenTime == missing (2^32 -1) we might do something, but not with 255.*/
     609                 : /*
     610                 :             if (lenTime == 255) {
     611                 :                lenTime = (inv->validTime -
     612                 :                           (inv->refTime + inv->foreSec)) / 3600;
     613                 :             }
     614                 : */
     615                 :             break;
     616                 :       }
     617                 :    }
     618                 : 
     619               2 :    if (timeRangeUnit == 255) {
     620               0 :       timeRangeUnit = 1;
     621                 :       lenTime = (sInt4) ((inv->validTime - inv->foreSec - inv->refTime) /
     622               0 :                          3600);
     623                 :    }
     624                 : /*   myAssert (timeRangeUnit == 1);*/
     625                 :    /* Try to convert lenTime to hourly. */
     626               2 :    if (timeRangeUnit == 0) {
     627               0 :       lenTime = (sInt4) (lenTime / 60.);
     628               0 :       timeRangeUnit = 1;
     629               2 :    } else if (timeRangeUnit == 1) {
     630               0 :    } else if (timeRangeUnit == 2) {
     631               0 :       lenTime = lenTime * 24;
     632               0 :       timeRangeUnit = 1;
     633               0 :    } else if (timeRangeUnit == 10) {
     634               0 :       lenTime = lenTime * 3;
     635               0 :       timeRangeUnit = 1;
     636               0 :    } else if (timeRangeUnit == 11) {
     637               0 :       lenTime = lenTime * 6;
     638               0 :       timeRangeUnit = 1;
     639               0 :    } else if (timeRangeUnit == 12) {
     640               0 :       lenTime = lenTime * 12;
     641               0 :       timeRangeUnit = 1;
     642               0 :    } else if (timeRangeUnit == 13) {
     643               0 :       lenTime = (sInt4) (lenTime / 3600.);
     644               0 :       timeRangeUnit = 1;
     645                 :    } else {
     646               0 :       printf ("Can't handle this timeRangeUnit\n");
     647                 :       myAssert (timeRangeUnit == 1);
     648                 :    }
     649               2 :    if (lenTime == GRIB2MISSING_s4) {
     650               0 :       lenTime = 0;
     651                 :    }
     652                 :    /* Find out what the name of this variable is. */
     653                 :    ParseElemName (center, subcenter, prodType, templat, cat, subcat,
     654                 :                   lenTime, timeIncrType, genID, probType, lowerProb,
     655                 :                   upperProb, &(inv->element), &(inv->comment),
     656               2 :                   &(inv->unitName), &convert, percentile);
     657                 : /*
     658                 :    if (strcmp (element, "") == 0) {
     659                 :       mallocSprintf (&(inv->element), "unknown");
     660                 :       mallocSprintf (&(inv->unitName), "[%s]", unitName);
     661                 :       if (strcmp (comment, "unknown") == 0) {
     662                 :          mallocSprintf (&(inv->comment), "(prodType %d, cat %d, subcat %d)"
     663                 :                         " [%s]", prodType, cat, subcat, unitName);
     664                 :       } else {
     665                 :          mallocSprintf (&(inv->comment), "%s [%s]", comment, unitName);
     666                 :       }
     667                 :    } else {
     668                 :       if (IsData_MOS (center, subcenter)) {
     669                 :          * See : http://www.nco.ncep.noaa.gov/pmb/docs/on388/tablea.html *
     670                 :          if (genID == 96) {
     671                 :             inv->element = (char *) malloc ((1 + 7 + strlen (element))
     672                 :                                             * sizeof (char));
     673                 :             sprintf (inv->element, "MOSGFS-%s", element);
     674                 :          } else {
     675                 :             inv->element = (char *) malloc ((1 + 4 + strlen (element))
     676                 :                                             * sizeof (char));
     677                 :             sprintf (inv->element, "MOS-%s", element);
     678                 :          }
     679                 :       } else {
     680                 :          inv->element = (char *) malloc ((1 + strlen (element))
     681                 :                                          * sizeof (char));
     682                 :          strcpy (inv->element, element);
     683                 :       }
     684                 :       mallocSprintf (&(inv->unitName), "[%s]", unitName);
     685                 :       mallocSprintf (&(inv->comment), "%s [%s]", comment, unitName);
     686                 : *
     687                 :       inv->unitName = (char *) malloc ((1 + 2 + strlen (unitName))
     688                 :                                        * sizeof (char));
     689                 :       sprintf (inv->unitName, "[%s]", unitName);
     690                 :       inv->comment = (char *) malloc ((1 + 3 + strlen (unitName) + strlen (comment))
     691                 :                                       * sizeof (char));
     692                 :       sprintf (inv->comment, "%s [%s]", comment, unitName);
     693                 : *
     694                 :    }
     695                 : */
     696                 : 
     697               2 :    if ((templat == GS4_RADAR) || (templat == GS4_SATELLITE)
     698                 :        || (templat == 254) || (templat == 1000) || (templat == 1001)
     699                 :        || (templat == 1002)) {
     700               0 :       reallocSprintf (&(inv->shortFstLevel), "0 undefined");
     701               0 :       reallocSprintf (&(inv->longFstLevel), "0.000[-] undefined ()");
     702                 :    } else {
     703               2 :       fstSurfType = (*buffer)[23 - 5];
     704               2 :       scale = (*buffer)[24 - 5];
     705               2 :       MEMCPY_BIG (&value, *buffer + 25 - 5, sizeof (sInt4));
     706               2 :       if ((value == GRIB2MISSING_s4) || (scale == GRIB2MISSING_s1)) {
     707               0 :          fstSurfValue = 0;
     708                 :       } else {
     709               2 :          fstSurfValue = value * pow (10.0, (int) (-1 * scale));
     710                 :       }
     711               2 :       sndSurfType = (*buffer)[29 - 5];
     712               2 :       scale = (*buffer)[30 - 5];
     713               2 :       MEMCPY_BIG (&value, *buffer + 31 - 5, sizeof (sInt4));
     714               4 :       if ((value == GRIB2MISSING_s4) || (scale == GRIB2MISSING_s1) ||
     715                 :           (sndSurfType == GRIB2MISSING_u1)) {
     716               2 :          sndSurfValue = 0;
     717               2 :          f_sndValue = 0;
     718                 :       } else {
     719               0 :          sndSurfValue = value * pow (10.0, -1 * scale);
     720               0 :          f_sndValue = 1;
     721                 :       }
     722                 : 
     723                 :       ParseLevelName (center, subcenter, fstSurfType, fstSurfValue,
     724                 :                       f_sndValue, sndSurfValue, &(inv->shortFstLevel),
     725               2 :                       &(inv->longFstLevel));
     726                 :    }
     727                 : 
     728                 :    /* Jump past section 5. */
     729               2 :    sectNum = 5;
     730               2 :    if (GRIB2SectJump (fp, gribLen, &sectNum, &secLen) != 0) {
     731               0 :       errSprintf ("ERROR: Problems Jumping past section 5\n");
     732               0 :       return -9;
     733                 :    }
     734                 :    /* Jump past section 6. */
     735               2 :    sectNum = 6;
     736               2 :    if (GRIB2SectJump (fp, gribLen, &sectNum, &secLen) != 0) {
     737               0 :       errSprintf ("ERROR: Problems Jumping past section 6\n");
     738               0 :       return -10;
     739                 :    }
     740                 :    /* Jump past section 7. */
     741               2 :    sectNum = 7;
     742               2 :    if (GRIB2SectJump (fp, gribLen, &sectNum, &secLen) != 0) {
     743               0 :       errSprintf ("ERROR: Problems Jumping past section 7\n");
     744               0 :       return -11;
     745                 :    }
     746               2 :    return 0;
     747                 : }
     748                 : 
     749                 : /*****************************************************************************
     750                 :  * GRIB2Inventory() -- Review 12/2002
     751                 :  *
     752                 :  * Arthur Taylor / MDL
     753                 :  *
     754                 :  * PURPOSE
     755                 :  *   Fills out an inventory structure for each GRIB message in a GRIB file,
     756                 :  * without calling the FORTRAN routines to unpack the message.  It returns
     757                 :  * the number of messages it found, or a negative number signifying an error.
     758                 :  *
     759                 :  * ARGUMENTS
     760                 :  * filename = File to do the inventory of. (Input)
     761                 :  *      Inv = The resultant array of inventories. (Output)
     762                 :  *   LenInv = Length of the Array Inv (Output)
     763                 :  *   numMsg = # of messages to inventory (0 = all, 1 = just first) (In)
     764                 :  *   msgNum = MsgNum to start with, MsgNum of last message (Input/Output)
     765                 :  *
     766                 :  * FILES/DATABASES:
     767                 :  *    Opens a GRIB2 file for reading given its filename.
     768                 :  *
     769                 :  * RETURNS: int (could use errSprintf())
     770                 :  * +# = number of GRIB2 messages in the file.
     771                 :  * -1 = Problems opening file for read.
     772                 :  * -2 = Problems in section 0
     773                 :  * -3 = Ran out of file.
     774                 :  * -4 = Problems Reading in section 1
     775                 :  * -5 = Problems Reading in section 2 or 3
     776                 :  * -6 = Problems Reading in section 3
     777                 :  * -7 = Problems Reading in section 4
     778                 :  * -8 = Problems Parsing section 4.
     779                 :  * -9 = Problems Reading in section 5
     780                 :  * -10 = Problems Reading in section 6
     781                 :  * -11 = Problems Reading in section 7
     782                 :  * -12 = Problems inventory'ing a GRIB1 record
     783                 :  * -13 = Problems inventory'ing a TDLP record
     784                 :  *
     785                 :  * HISTORY
     786                 :  *   9/2002 Arthur Taylor (MDL/RSIS): Created.
     787                 :  *  11/2002 AAT: Revised.
     788                 :  *  12/2002 (TK,AC,TB,&MS): Code Review.
     789                 :  *   3/2003 AAT: Corrected some satelite type mistakes.
     790                 :  *   3/2003 AAT: Implemented multiple grid inventories in the same GRIB2
     791                 :  *          message.
     792                 :  *   4/2003 AAT: Started adding GRIB1 support
     793                 :  *   6/2003 Matthew T. Kallio (matt@wunderground.com):
     794                 :  *          "wmo" dimension increased to WMO_HEADER_LEN + 1 (for '\0' char)
     795                 :  *   7/2003 AAT: Added numMsg so we can quickly find the reference time for
     796                 :  *          a file by inventorying just the first message.
     797                 :  *   8/2003 AAT: Adjusted use of GRIB_LIMIT to only affect the first message
     798                 :  *          after we know we have a GRIB file, we don't want "trailing" bytes
     799                 :  *          to break the program.
     800                 :  *   8/2003 AAT: switched fileLen to only be computed for an error message.
     801                 :  *   8/2003 AAT: curTot no longer serves a purpse.
     802                 :  *   5/2004 AAT: Added a check for section number 2..8 for the repeated
     803                 :  *          section (otherwise error)
     804                 :  *  10/2004 AAT: Added ability to inventory TDLP records.
     805                 :  *
     806                 :  * NOTES
     807                 :  *****************************************************************************
     808                 :  */
     809               3 : int GRIB2Inventory (DataSource &fp, inventoryType **Inv, uInt4 *LenInv,
     810                 :                     int numMsg, int *MsgNum)
     811                 : {
     812                 :    //FileDataSource fp (filename);            /* The opened GRIB2 file. */
     813               3 :    sInt4 offset = 0;    /* Where we are in the file. */
     814                 :    sInt4 msgNum;        /* Which GRIB2 message we are on. */
     815                 :    uInt4 gribLen;       /* Length of the current GRIB message. */
     816                 :    uInt4 secLen;        /* Length of current section. */
     817                 :    sChar sectNum;       /* Which section we are reading. */
     818                 :    char *buff;          /* Holds the info between records. */
     819                 :    uInt4 buffLen;       /* Length of info between records. */
     820                 :    sInt4 sect0[SECT0LEN_WORD]; /* Holds the current Section 0. */
     821               3 :    char *buffer = NULL; /* Holds a given section. */
     822               3 :    uInt4 bufferLen = 0; /* Size of buffer. */
     823                 :    inventoryType *inv;  /* Local ptr to Inv to reduce ptr confusion. */
     824                 :    inventoryType *lastInv; /* Used to point to last inventory record when
     825                 :                             * there are multiple grids in the same message. */
     826                 :    wordType word;       /* Used to parse the prodType out of Sect 0. */
     827                 :    int ans;             /* The return error code of ReadSect0. */
     828                 :    char *msg;           /* Used to pop messages off the error Stack. */
     829                 :    int version;         /* Which version of GRIB is in this message. */
     830                 :    uChar prodType;      /* Which GRIB2 type of product, 0 is meteo, 1 is
     831                 :                          * hydro, 2 is land, 3 is space, 10 is oceanographic. 
     832                 :                          */
     833                 :    int grib_limit;      /* How many bytes to look for before the first "GRIB" 
     834                 :                          * in the file.  If not found, is not a GRIB file. */
     835                 :    int c;               /* Determine if end of the file without fileLen. */
     836                 :    sInt4 fileLen;       /* Length of the GRIB2 file. */
     837                 :    unsigned short int center, subcenter; /* Who produced it. */
     838                 :    // char *ptr;           /* used to find the file extension. */
     839                 : 
     840               3 :    grib_limit = GRIB_LIMIT;
     841                 :    /*
     842                 :    if (filename != NULL) {
     843                 :       //if ((fp = fopen (filename, "rb")) == NULL) {
     844                 :       //   errSprintf ("ERROR: Problems opening %s for read.", filename);
     845                 :       //   return -1;
     846                 :       //}
     847                 :       //fp = FileDataSource(filename);
     848                 :       ptr = strrchr (filename, '.');
     849                 :       if (ptr != NULL) {
     850                 :          if (strcmp (ptr, ".tar") == 0) {
     851                 :             grib_limit = 5000;
     852                 :          }
     853                 :       }
     854                 :    } else {
     855                 :       //fp = stdin; // TODO!!
     856                 :    }
     857                 :    */
     858               3 :    msgNum = *MsgNum;
     859                 : 
     860               3 :    buff = NULL;
     861               3 :    buffLen = 0;
     862              24 :    while ((c = fp.DataSourceFgetc()) != EOF) {
     863              18 :      fp.DataSourceUngetc(c);
     864                 :       // ungetc (c, fp);
     865                 :       /* msgNum++ done first so any error messages range from 1..n, instead
     866                 :        * of 0.. n-1. Note msgNum should end up as n not (n-1) */
     867              18 :       msgNum++;
     868                 : /* Used when testing inventory of large TDLPack files. */
     869                 : /*
     870                 : #ifdef DEBUG
     871                 :       myAssert (msgNum < 32500L);
     872                 :       if (msgNum % 10 == 0) {
     873                 :          printf ("%ld :: %f\n", msgNum, clock () / (double) CLOCKS_PER_SEC);
     874                 :       }
     875                 : #endif
     876                 : */
     877                 :       /* Make it so the second, third, etc messages have no limit to finding
     878                 :        * the "GRIB" keyword. */
     879              18 :       if (msgNum > 1) {
     880              15 :          grib_limit = -1;
     881                 :       }
     882                 :       /* Read in the wmo header and sect0. */
     883              18 :       if (ReadSECT0 (fp, &buff, &buffLen, grib_limit, sect0, &gribLen,
     884                 :                      &version) < 0) {
     885               0 :          if (msgNum == 1) {
     886                 :             /* Handle case where we couldn't find 'GRIB' in the message. */
     887               0 :             preErrSprintf ("Inside GRIB2Inventory, Message # %d\n", msgNum);
     888               0 :             free (buffer);
     889               0 :             free (buff);
     890                 :             //fclose (fp);
     891               0 :             return -2;
     892                 :          } else {
     893                 :             /* Handle case where there are trailing bytes. */
     894               0 :             msg = errSprintf (NULL);
     895                 :             printf ("Warning: Inside GRIB2Inventory, Message # %d\n",
     896               0 :                     msgNum);
     897               0 :             printf ("%s", msg);
     898               0 :             free (msg);
     899                 :             /* find out how big the file is. */
     900               0 :             fp.DataSourceFseek (0L, SEEK_END);
     901               0 :             fileLen = fp.DataSourceFtell();
     902                 :             /* fseek (fp, 0L, SEEK_SET); */
     903                 :             printf ("There were %d trailing bytes in the file.\n",
     904               0 :                     fileLen - offset);
     905               0 :             free (buffer);
     906               0 :             free (buff);
     907                 :             //fclose (fp);
     908               0 :             return msgNum;
     909                 :          }
     910                 :       }
     911                 : 
     912                 :       /* Make room for this GRIB message in the inventory list. */
     913              18 :       *LenInv = *LenInv + 1;
     914                 :       *Inv = (inventoryType *) realloc ((void *) *Inv,
     915              18 :                                         *LenInv * sizeof (inventoryType));
     916              18 :       inv = *Inv + (*LenInv - 1);
     917                 : 
     918                 :       /* Start parsing the message. */
     919              18 :       inv->GribVersion = version;
     920              18 :       inv->msgNum = msgNum;
     921              18 :       inv->subgNum = 0;
     922              18 :       inv->start = offset;
     923              18 :       inv->element = NULL;
     924              18 :       inv->comment = NULL;
     925              18 :       inv->unitName = NULL;
     926              18 :       inv->shortFstLevel = NULL;
     927              18 :       inv->longFstLevel = NULL;
     928                 : 
     929              18 :       if (version == 1) {
     930              16 :          if (GRIB1_Inventory (fp, gribLen, inv) != 0) {
     931               0 :             preErrSprintf ("Inside GRIB2Inventory \n");
     932               0 :             free (buffer);
     933               0 :             free (buff);
     934                 :             //fclose (fp);
     935               0 :             return -12;
     936                 :          }
     937               2 :       } else if (version == -1) {
     938               0 :          if (TDLP_Inventory (fp, gribLen, inv) != 0) {
     939               0 :             preErrSprintf ("Inside GRIB2Inventory \n");
     940               0 :             free (buffer);
     941               0 :             free (buff);
     942                 :             //fclose (fp);
     943               0 :             return -13;
     944                 :          }
     945                 :       } else {
     946               2 :          word.li = sect0[1];
     947               2 :          prodType = word.buffer[2];
     948                 : 
     949                 :          /* Read section 1 into buffer. */
     950               2 :          sectNum = 1;
     951               2 :          if (GRIB2SectToBuffer (fp, gribLen, &sectNum, &secLen, &bufferLen,
     952                 :                                 &buffer) != 0) {
     953               0 :             errSprintf ("ERROR: Problems with section 1\n");
     954               0 :             free (buffer);
     955               0 :             free (buff);
     956                 :             //fclose (fp);
     957               0 :             return -4;
     958                 :          }
     959                 :          /* Parse the interesting data out of sect 1. */
     960               2 :          InventoryParseTime (buffer + 13 - 5, &(inv->refTime));
     961               2 :          MEMCPY_BIG (&center, buffer + 6 - 5, sizeof (short int));
     962               2 :          MEMCPY_BIG (&subcenter, buffer + 8 - 5, sizeof (short int));
     963                 : 
     964               2 :          sectNum = 2;
     965               2 :          do {
     966                 :             /* Look at sections 2 to 7 */
     967               2 :             if ((ans = GRIB2Inventory2to7 (sectNum, fp, gribLen, &bufferLen,
     968                 :                                            &buffer, inv, prodType, center,
     969                 :                                            subcenter)) != 0) {
     970                 :                //fclose (fp);
     971               0 :                free (buffer);
     972               0 :                free (buff);
     973               0 :                return ans;
     974                 :             }
     975                 :             /* Try to read section 8. If it is "7777" = 926365495 regardless
     976                 :              * of endian'ness then we have a simple message, otherwise it is
     977                 :              * complex, and we need to read more. */
     978               2 :             if (FREAD_BIG (&secLen, sizeof (sInt4), 1, fp) != 1) {
     979               0 :                errSprintf ("ERROR: Ran out of file looking for Sect 8.\n");
     980               0 :                free (buffer);
     981               0 :                free (buff);
     982                 :                // fclose (fp);
     983               0 :                return -4;
     984                 :             }
     985               2 :             if (secLen == 926365495L) {
     986               2 :                sectNum = 8;
     987                 :             } else {
     988               0 :                if (fp.DataSourceFread (&sectNum, sizeof (char), 1) != 1) {
     989                 :                   errSprintf ("ERROR: Ran out of file looking for "
     990               0 :                               "subMessage.\n");
     991               0 :                   free (buffer);
     992               0 :                   free (buff);
     993                 :                   //fclose (fp);
     994               0 :                   return -4;
     995                 :                }
     996               0 :                if ((sectNum < 2) || (sectNum > 7)) {
     997                 :                   errSprintf ("ERROR (GRIB2Inventory): Couldn't find the end"
     998               0 :                               " of message\n");
     999               0 :                   errSprintf ("and it doesn't appear to repeat sections.\n");
    1000               0 :                   errSprintf ("so it is probably an ASCII / binary bug\n");
    1001               0 :                   free (buffer);
    1002               0 :                   free (buff);
    1003                 :                   //fclose (fp);
    1004               0 :                   return -4;
    1005                 :                }
    1006               0 :                fp.DataSourceFseek (-5, SEEK_CUR);
    1007                 :                /* Make room for the next part of this GRIB message in the
    1008                 :                 * inventory list.  This is for when we have sub-grids. */
    1009               0 :                *LenInv = *LenInv + 1;
    1010                 :                *Inv = (inventoryType *) realloc ((void *) *Inv,
    1011                 :                                                  *LenInv *
    1012               0 :                                                  sizeof (inventoryType));
    1013               0 :                inv = *Inv + (*LenInv - 1);
    1014               0 :                lastInv = *Inv + (*LenInv - 2);
    1015                 : 
    1016               0 :                inv->GribVersion = version;
    1017               0 :                inv->msgNum = msgNum;
    1018               0 :                inv->subgNum = lastInv->subgNum + 1;
    1019               0 :                inv->start = offset;
    1020               0 :                inv->element = NULL;
    1021               0 :                inv->comment = NULL;
    1022               0 :                inv->unitName = NULL;
    1023               0 :                inv->shortFstLevel = NULL;
    1024               0 :                inv->longFstLevel = NULL;
    1025                 : 
    1026               0 :                word.li = sect0[1];
    1027               0 :                prodType = word.buffer[2];
    1028               0 :                inv->refTime = lastInv->refTime;
    1029                 :             }
    1030                 :          } while (sectNum != 8);
    1031                 :       }
    1032                 : 
    1033                 :       /* added to inventory either first msgNum messages, or all messages */
    1034              18 :       if (numMsg == msgNum) {
    1035               0 :          break;
    1036                 :       }
    1037                 :       /* Continue on to the next GRIB2 message. */
    1038              18 :       if (version == -1) {
    1039                 :          /* TDLPack uses 4 bytes for FORTRAN record size, then another 8
    1040                 :           * bytes for the size of the record (so FORTRAN can see it), then
    1041                 :           * the data rounded up to an 8 byte boundary, then a trailing 4
    1042                 :           * bytes for a final FORTRAN record size.  However it only stores
    1043                 :           * in_ the gribLen the non-rounded amount, so we need to take care
    1044                 :           * of the rounding, and the trailing 4 bytes here. */
    1045               0 :          offset += buffLen + ((sInt4) ceil (gribLen / 8.0)) * 8 + 4;
    1046                 :       } else {
    1047              18 :          offset += buffLen + gribLen;
    1048                 :       }
    1049              18 :       fp.DataSourceFseek (offset, SEEK_SET);
    1050                 :    }
    1051               3 :    free (buffer);
    1052               3 :    free (buff);
    1053                 :    //fclose (fp);
    1054               3 :    *MsgNum = msgNum;
    1055               3 :    return msgNum;
    1056                 : }
    1057                 : 
    1058               0 : int GRIB2RefTime (char *filename, double *refTime)
    1059                 : {
    1060               0 :    FileDataSource fp (filename);            /* The opened GRIB2 file. */
    1061               0 :    sInt4 offset = 0;    /* Where we are in the file. */
    1062                 :    sInt4 msgNum;        /* Which GRIB2 message we are on. */
    1063                 :    uInt4 gribLen;       /* Length of the current GRIB message. */
    1064                 :    uInt4 secLen;        /* Length of current section. */
    1065                 :    sChar sectNum;       /* Which section we are reading. */
    1066                 :    char *buff;          /* Holds the info between records. */
    1067                 :    uInt4 buffLen;       /* Length of info between records. */
    1068                 :    sInt4 sect0[SECT0LEN_WORD]; /* Holds the current Section 0. */
    1069               0 :    char *buffer = NULL; /* Holds a given section. */
    1070               0 :    uInt4 bufferLen = 0; /* Size of buffer. */
    1071                 :    wordType word;       /* Used to parse the prodType out of Sect 0. */
    1072                 :    int ans;             /* The return error code of ReadSect0. */
    1073                 :    char *msg;           /* Used to pop messages off the error Stack. */
    1074                 :    int version;         /* Which version of GRIB is in this message. */
    1075                 :    uChar prodType;      /* Which GRIB2 type of product, 0 is meteo, 1 is
    1076                 :                          * hydro, 2 is land, 3 is space, 10 is oceanographic. 
    1077                 :                          */
    1078                 :    int grib_limit;      /* How many bytes to look for before the first "GRIB" 
    1079                 :                          * in the file.  If not found, is not a GRIB file. */
    1080                 :    int c;               /* Determine if end of the file without fileLen. */
    1081                 :    sInt4 fileLen;       /* Length of the GRIB2 file. */
    1082                 :    char *ptr;           /* used to find the file extension. */
    1083                 :    double refTime1;
    1084                 : 
    1085               0 :    grib_limit = GRIB_LIMIT;
    1086               0 :    if (filename != NULL) {
    1087                 :       //if ((fp = fopen (filename, "rb")) == NULL) {
    1088                 :       //   errSprintf ("ERROR: Problems opening %s for read.", filename);
    1089                 :       //   return -1;
    1090                 :       //}
    1091                 :       //fp = DataSource(filename);
    1092               0 :       ptr = strrchr (filename, '.');
    1093               0 :       if (ptr != NULL) {
    1094               0 :          if (strcmp (ptr, ".tar") == 0) {
    1095               0 :             grib_limit = 5000;
    1096                 :          }
    1097                 :       }
    1098                 :    } else {
    1099                 :       // fp = stdin; // TODO!!
    1100                 :    }
    1101               0 :    msgNum = 0;
    1102                 : 
    1103               0 :    buff = NULL;
    1104               0 :    buffLen = 0;
    1105               0 :    while ((c = fp.DataSourceFgetc()) != EOF) {
    1106               0 :      fp.DataSourceUngetc(c);
    1107                 :       /* msgNum++ done first so any error messages range from 1..n, instead
    1108                 :        * of 0.. n-1. Note msgNum should end up as n not (n-1) */
    1109               0 :       msgNum++;
    1110                 :       /* Make it so the second, third, etc messages have no limit to finding
    1111                 :        * the "GRIB" keyword. */
    1112               0 :       if (msgNum > 1) {
    1113               0 :          grib_limit = -1;
    1114                 :       }
    1115                 :       /* Read in the wmo header and sect0. */
    1116               0 :       if ((ans = ReadSECT0 (fp, &buff, &buffLen, grib_limit, sect0, &gribLen,
    1117                 :                             &version)) < 0) {
    1118               0 :          if (msgNum == 1) {
    1119                 :             /* Handle case where we couldn't find 'GRIB' in the message. */
    1120               0 :             preErrSprintf ("Inside GRIB2RefTime, Message # %d\n", msgNum);
    1121               0 :             free (buffer);
    1122               0 :             free (buff);
    1123                 :             //fclose (fp);
    1124               0 :             return -2;
    1125                 :          } else {
    1126                 :             /* Handle case where there are trailing bytes. */
    1127               0 :             msg = errSprintf (NULL);
    1128               0 :             printf ("Warning: Inside GRIB2RefTime, Message # %d\n", msgNum);
    1129               0 :             printf ("%s", msg);
    1130               0 :             free (msg);
    1131                 :             /* find out how big the file is. */
    1132               0 :             fp.DataSourceFseek (0L, SEEK_END);
    1133               0 :             fileLen = fp.DataSourceFtell();
    1134                 :             /* fseek (fp, 0L, SEEK_SET); */
    1135                 :             printf ("There were %d trailing bytes in the file.\n",
    1136               0 :                     fileLen - offset);
    1137               0 :             free (buffer);
    1138               0 :             free (buff);
    1139                 :             //fclose (fp);
    1140               0 :             return msgNum;
    1141                 :          }
    1142                 :       }
    1143                 : 
    1144               0 :       if (version == 1) {
    1145               0 :          if (GRIB1_RefTime (fp, gribLen, &(refTime1)) != 0) {
    1146               0 :             preErrSprintf ("Inside GRIB1_RefTime\n");
    1147               0 :             free (buffer);
    1148               0 :             free (buff);
    1149                 :             //fclose (fp);
    1150               0 :             return -12;
    1151                 :          }
    1152               0 :       } else if (version == -1) {
    1153               0 :          if (TDLP_RefTime (fp, gribLen, &(refTime1)) != 0) {
    1154               0 :             preErrSprintf ("Inside TDLP_RefTime\n");
    1155               0 :             free (buffer);
    1156               0 :             free (buff);
    1157                 :             //fclose (fp);
    1158               0 :             return -13;
    1159                 :          }
    1160                 :       } else {
    1161               0 :          word.li = sect0[1];
    1162               0 :          prodType = word.buffer[2];
    1163                 : 
    1164                 :          /* Read section 1 into buffer. */
    1165               0 :          sectNum = 1;
    1166               0 :          if (GRIB2SectToBuffer (fp, gribLen, &sectNum, &secLen, &bufferLen,
    1167                 :                                 &buffer) != 0) {
    1168               0 :             errSprintf ("ERROR: Problems with section 1\n");
    1169               0 :             free (buffer);
    1170                 :             //fclose (fp);
    1171               0 :             return -4;
    1172                 :          }
    1173                 :          /* Parse the interesting data out of sect 1. */
    1174               0 :          InventoryParseTime (buffer + 13 - 5, &(refTime1));
    1175                 :       }
    1176               0 :       if (msgNum == 1) {
    1177               0 :          *refTime = refTime1;
    1178                 :       } else {
    1179               0 :          if (*refTime > refTime1) {
    1180               0 :             *refTime = refTime1;
    1181                 :          }
    1182                 :       }
    1183                 : 
    1184                 :       /* Continue on to the next GRIB2 message. */
    1185               0 :       offset += gribLen + buffLen;
    1186               0 :       fp.DataSourceFseek (offset, SEEK_SET);
    1187                 :    }
    1188               0 :    free (buffer);
    1189               0 :    free (buff);
    1190                 :    //fclose (fp);
    1191               0 :    return 0;
    1192                 : }

Generated by: LCOV version 1.7