Example #1
0
/*****************************************************************************
 * GDSValid() --
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *   Validates GDS for use with the current mapping library routines.
 *
 * ARGUMENTS
 * gds = The filled in section 3 data to check. (Input)
 *
 * FILES/DATABASES: None
 *
 * RETURNS: int (could use errSprintf())
 *  0 = Ok.
 * -1 = Something was wrong with section 3.
 *
 * HISTORY
 *  12/2002 Arthur Taylor (MDL/RSIS): Created.
 *   5/2003 AAT: Enabled other spherical earths.
 *   6/2003 AAT: Enabled Dx != Dy (by taking average).
 *   1/2004 AAT: Emapf now supports elliptical earth.
 *
 * NOTES
 *****************************************************************************
 */
int GDSValid (const gdsType *gds)
{
   if (gds->numPts != gds->Ny * gds->Nx) {
      errSprintf ("ERROR: numPts != Nx * Ny? (%ld != %ld * %ld)",
                  gds->numPts, gds->Nx, gds->Ny);
      return -1;
   }

   /* Add GS3_LATLON ? */

   if ((gds->projType != GS3_MERCATOR) && (gds->projType != GS3_POLAR) &&
       (gds->projType != GS3_LAMBERT) && (gds->projType != GS3_LATLON)) {
      errSprintf ("Projection code can not handle this projection yet. \n"
                  "See section 3 template type %d\n", gds->projType);
      return -1;
   }
/* Emapf now supports elipsoidal earth
   if (!gds->f_sphere) {
      errSprintf ("Projection code can not handle a non-sphere yet.");
      return -1;
   }
*/
   if ((gds->Dx <= 0) || (gds->Dy <= 0)) {
      errSprintf ("Projection code requires Dx (%f) > 0 and Dy (%f) > 0",
                  gds->Dx, gds->Dy);
      return -1;
   }
   return 0;
}
Example #2
0
/*****************************************************************************
 * FindSectLen() -- Review 12/2002
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *   Looks through a GRIB message and finds out how big each section is.
 *
 * ARGUMENTS
 * c_ipack = The current GRIB2 message. (Input)
 * gribLen = Length of c_ipack. (Input)
 *      ns = Array of section lengths. (Output)
 *   nd2x3 = Total number of grid points (Output)
 * table50 = Type of packing used. (See code table 5.0) (GS5_SIMPLE = 0,
 *           GS5_CMPLX = 2, GS5_CMPLXSEC = 3) (Output)
 *
 * FILES/DATABASES: None
 *
 * RETURNS: int (could use errSprintf())
 *  0 = OK
 * -1 = Ran of data in a section
 * -2 = Section not properly labeled.
 *
 * HISTORY
 *   9/2002 Arthur Taylor (MDL/RSIS): Created.
 *  11/2002 AAT: Updated.
 *  12/2002 (TK,AC,TB,&MS): Code Review.
 *   3/2003 AAT: Made it handle multiple grids in the same GRIB2 message.
 *   5/2003 AAT: Bug: Initialized size of section 2..6 to -1, instead
 *               of 2..7.
 *
 * NOTES
 * 1) Assumes that the pack method of multiple grids are the same.
 *****************************************************************************
 */
static int FindSectLen (char *c_ipack, sInt4 gribLen, sInt4 ns[8],
                        sInt4 *nd2x3, short int *table50)
{
   sInt4 curTot;        /* Where we are in the current GRIB message. */
   char sectNum;        /* Which section we are working with. */
   int ans;             /* The return error code of FindSectLen2to7. */
   sInt4 sectLen;       /* The length of the current section. */
   int i;               /* counter as we init ns[]. */

   ns[0] = SECT0LEN_WORD * 4;
   curTot = ns[0];

   /* Figure out the size of section 1. */
   if (curTot + 5 > gribLen) {
      errSprintf ("ERROR: Ran out of data in Section 1\n");
      return -1;
   }
   if (c_ipack[curTot + 4] != 1) {
      errSprintf ("ERROR: Section 1 labeled as %d\n", c_ipack[curTot + 4]);
      return -2;
   }
   MEMCPY_BIG (&(ns[1]), c_ipack + curTot, 4);
   curTot += ns[1];
/*
#ifdef DEBUG
   printf ("Section len (0=%ld) (1=%ld)\n", ns[0], ns[1]);
#endif
*/
   sectNum = 2;
   for (i = 2; i < 8; i++) {
      ns[i] = -1;
   }
   *nd2x3 = -1;
   do {
      if ((ans = FindSectLen2to7 (c_ipack, gribLen, ns, sectNum, &curTot,
                                  nd2x3, table50)) != 0) {
         return ans;
      }
      /* Try to read section 8.  If it is "7777" == 926365495 regardless of
       * endian'ness then we have a simple message, otherwise it is complex,
       * and we need to read more. */
      memcpy (&sectLen, c_ipack + curTot, 4);
      if (sectLen == 926365495L) {
         sectNum = 8;
      } else {
         sectNum = c_ipack[curTot + 4];
         if ((sectNum < 2) || (sectNum > 7)) {
            errSprintf ("ERROR (FindSectLen): Couldn't find the end of the "
                        "message\n");
            errSprintf ("and it doesn't appear to repeat sections.\n");
            errSprintf ("so it is probably an ASCII / binary bug\n");
            errSprintf ("Max Sect Lengths: %ld %ld %ld %ld %ld %ld %ld"
                        " %ld\n", ns[0], ns[1], ns[2], ns[3], ns[4], ns[5],
                        ns[6], ns[7]);
            return -2;
         }
      }
   } while (sectNum != 8);
   return 0;
}
Example #3
0
/* 1) find lwlf coresponding x1,y1, and uprt corresponding x2,y2
 * 2) create a new gds based on old one, but shifted with lwlf in bottom
 *    left, and uprt in upper right.
 * 3) Shift data around on grid? create new grid and copy data?
 */
int computeSubGrid (LatLon *lwlf, int *x1, int *y1, LatLon *uprt, int *x2,
                    int *y2, gdsType *gds, gdsType *newGds)
{
   myMaparam map;       /* Used to compute the grid lat/lon points. */
   double x, y;

   /* Check that gds is valid before setting up map projection. */
   if (GDSValid (gds) != 0) {
      preErrSprintf ("ERROR: gds was not Valid.\n");
      return -1;
   }

   /* Validate that lwlf < uprt */
   if (lwlf->lat > uprt->lat) {
      x = lwlf->lat;
      lwlf->lat = uprt->lat;
      uprt->lat = x;
   }
   if (lwlf->lon > uprt->lon) {
      x = lwlf->lon;
      lwlf->lon = uprt->lon;
      uprt->lon = x;
   }

   /* Set up the map projection. */
   SetMapParamGDS (&map, gds);
   myCll2xy (&map, lwlf->lat, lwlf->lon, &x, &y);
   *x1 = (int) floor (x);
   *y1 = (int) floor (y);
   myCll2xy (&map, uprt->lat, uprt->lon, &x, &y);
   *x2 = (int) ceil (x);
   *y2 = (int) ceil (y);
   if ((*x1 >= *x2) || (*y1 >= *y2)) {
      errSprintf ("ERROR: subgrid is not at least one cell wide/high\n");
      return -1;
   }

   myAssert ((gds->projType == GS3_LATLON) || (gds->projType == GS3_POLAR) ||
             (gds->projType == GS3_LAMBERT) ||
             (gds->projType == GS3_MERCATOR));
   memcpy (newGds, gds, sizeof (gdsType));
   newGds->Nx = *x2 - *x1 + 1;
   newGds->Ny = *y2 - *y1 + 1;
   newGds->numPts = (newGds->Nx * newGds->Ny);
   myCxy2ll (&map, (double) (*x1), (double) (*y1), &(newGds->lat1),
             &(newGds->lon1));
   if (gds->projType == GS3_LATLON) {
      myCxy2ll (&map, (double) (*x2), (double) (*y2), &(newGds->lat2),
                &(newGds->lon2));
   }
   return 0;
}
Example #4
0
/*****************************************************************************
 * GRIB2SectToBuffer() -- Review 12/2002
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *    To read in a GRIB2 section into a buffer.  Reallocates space for the
 * section if buffLen < secLen.  Reads in secLen and checks that the section
 * is valid, and the file is large enough to hold the entire section.
 *
 * ARGUMENTS
 *      fp = Opened file pointing to the section in question. (Input/Output)
 * gribLen = The total length of the grib message. (Input)
 *    sect = Which section we think we are reading.
 *           If it is -1, then set it to the section the file says we are
 *           reading (useful for optional sect 2)) (Input/Output).
 *  secLen = The length of this section (Output)
 * buffLen = Allocated length of buff (Input/Output)
 *    buff = Stores the section (Output)
 *
 * FILES/DATABASES:
 *    An already opened GRIB2 file pointer, already at section in question.
 *
 * RETURNS: int (could use errSprintf())
 *  0 = Ok.
 * -1 = Ran out of file.
 * -2 = Section was miss-labeled.
 *
 * HISTORY
 *  11/2002 Arthur Taylor (MDL/RSIS): Created.
 *  12/2002 (TK,AC,TB,&MS): Code Review.
 *   8/2003 AAT: Removed dependence on curTot
 *
 * NOTES
 *   May want to put this in degrib2.c
 *****************************************************************************
 */
static int GRIB2SectToBuffer (DataSource &fp,
                              CPL_UNUSED uInt4 gribLen,
                              sChar *sect,
                              uInt4 *secLen, uInt4 *buffLen, char **buff)
{
   char *buffer = *buff; /* Local ptr to buff to reduce ptr confusion. */

   if (FREAD_BIG (secLen, sizeof (sInt4), 1, fp) != 1) {
      if (*sect != -1) {
         errSprintf ("ERROR: Ran out of file in Section %d\n", *sect);
      } else {
         errSprintf ("ERROR: Ran out of file in GRIB2SectToBuffer\n");
      }
      return -1;
   }
   if( *secLen < sizeof(sInt4) )
   {
       errSprintf ("ERROR: Wrong secLen in GRIB2SectToBuffer\n");
       return -1;
   }
   if (*buffLen < *secLen) {
      char* buffnew = (char *) realloc ((void *) *buff, *secLen * sizeof (char));
      if( buffnew == NULL )
      {
           errSprintf ("ERROR: Ran out of memory in GRIB2SectToBuffer\n");
           return -1;
      }
      *buffLen = *secLen;
      *buff = buffnew;
      buffer = *buff;
   }

   if (fp.DataSourceFread (buffer, sizeof (char), *secLen - sizeof (sInt4)) !=
       *secLen - sizeof (sInt4)) {
      if (*sect != -1) {
         errSprintf ("ERROR: Ran out of file in Section %d\n", *sect);
      } else {
         errSprintf ("ERROR: Ran out of file in GRIB2SectToBuffer\n");
      }
      return -1;
   }
   if (*sect == -1) {
      *sect = buffer[5 - 5];
   } else if (buffer[5 - 5] != *sect) {
      errSprintf ("ERROR: Section %d mislabeled\n", *sect);
      return -2;
   }
   return 0;
}
Example #5
0
void GRIBRasterBand::ReadGribData( DataSource & fp, sInt4 start, int subgNum, double** data, grib_MetaData** metaData)
{
    /* Initialisation, for calling the ReadGrib2Record function */
    sInt4 f_endMsg = 1;  /* 1 if we read the last grid in a GRIB message, or we haven't read any messages. */
    // int subgNum = 0;     /* The subgrid in the message that we are interested in. */
    sChar f_unit = 2;        /* None = 0, English = 1, Metric = 2 */
    double majEarth = 0;     /* -radEarth if < 6000 ignore, otherwise use this to
                              * override the radEarth in the GRIB1 or GRIB2
                              * message.  Needed because NCEP uses 6371.2 but GRIB1 could only state 6367.47. */
    double minEarth = 0;     /* -minEarth if < 6000 ignore, otherwise use this to
                              * override the minEarth in the GRIB1 or GRIB2 message. */
    sChar f_SimpleVer = 4;   /* Which version of the simple NDFD Weather table to
                              * use. (1 is 6/2003) (2 is 1/2004) (3 is 2/2004)
                              * (4 is 11/2004) (default 4) */
    LatLon lwlf;         /* lower left corner (cookie slicing) -lwlf */
    LatLon uprt;         /* upper right corner (cookie slicing) -uprt */
    IS_dataType is;      /* Un-parsed meta data for this GRIB2 message. As well as some memory used by the unpacker. */

    lwlf.lat = -100; // lat == -100 instructs the GRIB decoder that we don't want a subgrid

    IS_Init (&is);

    const char* pszGribNormalizeUnits = CPLGetConfigOption("GRIB_NORMALIZE_UNITS", NULL);
    if ( pszGribNormalizeUnits != NULL && ( STRCASECMP(pszGribNormalizeUnits,"NO")==0 ) )
        f_unit = 0; /* do not normalize units to metric */

    /* Read GRIB message from file position "start". */
    fp.DataSourceFseek(start, SEEK_SET);
    uInt4 grib_DataLen = 0;  /* Size of Grib_Data. */
    *metaData = new grib_MetaData();
    MetaInit (*metaData);
    ReadGrib2Record (fp, f_unit, data, &grib_DataLen, *metaData, &is, subgNum,
                     majEarth, minEarth, f_SimpleVer, &f_endMsg, &lwlf, &uprt);

    char * errMsg = errSprintf(NULL); // no intention to show errors, just swallow it and free the memory
    if( errMsg != NULL )
        CPLDebug( "GRIB", "%s", errMsg );
    free(errMsg);
    IS_Free(&is);
}
Example #6
0
/*****************************************************************************
 * GRIB2SectJump() --
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *    To jump past a GRIB2 section.  Reads in secLen and checks that the
 * section is valid.
 *
 * ARGUMENTS
 *      fp = Opened file pointing to the section in question. (Input/Output)
 * gribLen = The total length of the grib message. (Input)
 *    sect = Which section we think we are reading.
 *           If it is -1, then set it to the section the file says we are
 *           reading (useful for optional sect 2)) (Input/Output).
 *  secLen = The length of this section (Output)
 *
 * FILES/DATABASES:
 *    An already opened GRIB2 file pointer, already at section in question.
 *
 * RETURNS: int (could use errSprintf())
 *  0 = Ok.
 * -1 = Ran out of file.
 * -2 = Section was miss-labeled.
 *
 * HISTORY
 *   3/2003 Arthur Taylor (MDL/RSIS): Created.
 *   8/2003 AAT: Removed dependence on curTot, which was used to compute if
 *          the file should be large enough for the fseek, but didn't check
 *          if it actually was.
 *
 * NOTES
 *   May want to put this in degrib2.c
 *****************************************************************************
 */
static int GRIB2SectJump (DataSource &fp,
                          CPL_UNUSED sInt4 gribLen, sChar *sect, uInt4 *secLen)
{
   char sectNum;        /* Validates that we are on the correct section. */
   int c;               /* Check that the fseek is still inside the file. */

   if (FREAD_BIG (secLen, sizeof (sInt4), 1, fp) != 1) {
      if (*sect != -1) {
         errSprintf ("ERROR: Ran out of file in Section %d\n", *sect);
      } else {
         errSprintf ("ERROR: Ran out of file in GRIB2SectSkip\n");
      }
      return -1;
   }
   if (fp.DataSourceFread (&sectNum, sizeof (char), 1) != 1) {
      if (*sect != -1) {
         errSprintf ("ERROR: Ran out of file in Section %d\n", *sect);
      } else {
         errSprintf ("ERROR: Ran out of file in GRIB2SectSkip\n");
      }
      return -1;
   }
   if (*sect == -1) {
      *sect = sectNum;
   } else if (sectNum != *sect) {
       errSprintf ("ERROR: Section %d mislabeled\n", *sect);
       return -2;
   }
   /* Since fseek does not give an error if we jump outside the file, we test
    * it by using fgetc / ungetc. */
   fp.DataSourceFseek (*secLen - 5, SEEK_CUR);
   if ((c = fp.DataSourceFgetc()) == EOF) {
       errSprintf ("ERROR: Ran out of file in Section %d\n", *sect);
       return -1;
   } else {
       fp.DataSourceUngetc(c);
   }
   return 0;
}
Example #7
0
GDALDataset *GRIBDataset::Open( GDALOpenInfo * poOpenInfo )

{
    if( !Identify(poOpenInfo) )
        return NULL;
        
/* -------------------------------------------------------------------- */
/*      A fast "probe" on the header that is partially read in memory.  */
/* -------------------------------------------------------------------- */
    char *buff = NULL;
    uInt4 buffLen = 0;
    sInt4 sect0[SECT0LEN_WORD];
    uInt4 gribLen;
    int version;
// grib is not thread safe, make sure not to cause problems
// for other thread safe formats
    static void *mutex = 0;
    CPLMutexHolderD(&mutex);
    MemoryDataSource mds (poOpenInfo->pabyHeader, poOpenInfo->nHeaderBytes);
    if (ReadSECT0 (mds, &buff, &buffLen, -1, sect0, &gribLen, &version) < 0) {
        free (buff);
        char * errMsg = errSprintf(NULL);
        if( errMsg != NULL && strstr(errMsg,"Ran out of file") == NULL )
            CPLDebug( "GRIB", "%s", errMsg );
        free(errMsg);
        return NULL;
    }
    free(buff);
    
/* -------------------------------------------------------------------- */
/*      Confirm the requested access is supported.                      */
/* -------------------------------------------------------------------- */
    if( poOpenInfo->eAccess == GA_Update )
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "The GRIB driver does not support update access to existing"
                  " datasets.\n" );
        return NULL;
    }
/* -------------------------------------------------------------------- */
/*      Create a corresponding GDALDataset.                             */
/* -------------------------------------------------------------------- */
    GRIBDataset 	*poDS;

    poDS = new GRIBDataset();

    poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r" );

	/* Check the return values */    
	if (!poDS->fp) {
        // we have no FP, so we don't have anywhere to read from
        char * errMsg = errSprintf(NULL);
        if( errMsg != NULL )
            CPLDebug( "GRIB", "%s", errMsg );
        free(errMsg);
		
		CPLError( CE_Failure, CPLE_OpenFailed, "Error (%d) opening file %s", errno, poOpenInfo->pszFilename);
        delete poDS;
        return NULL;
	}
    
/* -------------------------------------------------------------------- */
/*      Read the header.                                                */
/* -------------------------------------------------------------------- */

/* -------------------------------------------------------------------- */
/*      Make an inventory of the GRIB file.                             */
/* The inventory does not contain all the information needed for        */
/* creating the RasterBands (especially the x and y size), therefore    */
/* the first GRIB band is also read for some additional metadata.       */
/* The band-data that is read is stored into the first RasterBand,      */
/* simply so that the same portion of the file is not read twice.       */
/* -------------------------------------------------------------------- */
    
    VSIFSeekL( poDS->fp, 0, SEEK_SET );

    FileDataSource grib_fp (poDS->fp);

    inventoryType *Inv = NULL;  /* Contains an GRIB2 message inventory of the file */
    uInt4 LenInv = 0;        /* size of Inv (also # of GRIB2 messages) */
    int msgNum =0;          /* The messageNumber during the inventory. */

    if (GRIB2Inventory (grib_fp, &Inv, &LenInv, 0, &msgNum) <= 0 )
    {
        char * errMsg = errSprintf(NULL);
        if( errMsg != NULL )
            CPLDebug( "GRIB", "%s", errMsg );
        free(errMsg);

        CPLError( CE_Failure, CPLE_OpenFailed, 
                  "%s is a grib file, but no raster dataset was successfully identified.",
                  poOpenInfo->pszFilename );
        delete poDS;
        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Create band objects.                                            */
/* -------------------------------------------------------------------- */
    for (uInt4 i = 0; i < LenInv; ++i)
    {
        uInt4 bandNr = i+1;
        if (bandNr == 1)
        {
            // important: set DataSet extents before creating first RasterBand in it
            double * data = NULL;
            grib_MetaData* metaData;
            GRIBRasterBand::ReadGribData(grib_fp, 0, Inv[i].subgNum, &data, &metaData);
            if (data == 0 || metaData->gds.Nx < 1 || metaData->gds.Ny < 1)
            {
                CPLError( CE_Failure, CPLE_OpenFailed, 
                          "%s is a grib file, but no raster dataset was successfully identified.",
                          poOpenInfo->pszFilename );
                delete poDS;
                return NULL;
            }

            poDS->SetGribMetaData(metaData); // set the DataSet's x,y size, georeference and projection from the first GRIB band
            GRIBRasterBand* gribBand = new GRIBRasterBand( poDS, bandNr, Inv+i);

            if( Inv->GribVersion == 2 )
                gribBand->FindPDSTemplate();

            gribBand->m_Grib_Data = data;
            gribBand->m_Grib_MetaData = metaData;
            poDS->SetBand( bandNr, gribBand);
        }
        else
            poDS->SetBand( bandNr, new GRIBRasterBand( poDS, bandNr, Inv+i ));
        GRIB2InventoryFree (Inv + i);
    }
    free (Inv);

/* -------------------------------------------------------------------- */
/*      Initialize any PAM information.                                 */
/* -------------------------------------------------------------------- */
    poDS->SetDescription( poOpenInfo->pszFilename );
    poDS->TryLoadXML();

/* -------------------------------------------------------------------- */
/*      Check for external overviews.                                   */
/* -------------------------------------------------------------------- */
    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );

    return( poDS );
}
Example #8
0
/*****************************************************************************
 * gribDraw() --
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *   This use GD to create an image based on the grid and a control file.
 *
 * ARGUMENTS
 *   Filename = Name of file to save to. (Input)
 *  grib_Data = The grib2 data to write. (Input)
 * mapIniFile = Name of the mapIni file to control the draws. (Input)
 *       meta = Meta Data about the grid. (Input)
 *        usr = User specified options. (Input)
 *
 * RETURNS: int (could use errSprintf())
 *  0 = OK
 *
 * HISTORY
 *  10/2005 Arthur Taylor (MDL): Created.
 *
 * NOTES
 *****************************************************************************
 */
int drawGrib (const char *Filename, double *grib_Data,
              const char *mapIniFile, const char *mapIniOptions,
              gdsType *gds, double Min, double Max, sChar f_missing,
              double missing, grib_MetaData *meta, userType *usr)
{
   mapIniType mapIni;
   myMaparam map;       /* Used to compute the grid lat/lon points. */
#ifdef TESTING
   double lat, lon;
#endif
   size_t nameLen = strlen (Filename);
   double orientLon;
   FILE *fp;
   int i;

#ifdef DEBUG
   printf ("start drawGrib. %f\n", clock () / (double) (CLOCKS_PER_SEC));
#endif

   if (nameLen < 4) {
      errSprintf ("ERROR: File %s is too short in length (it may need an "
                  "extension?)", Filename);
      return -2;
   }

   /* Set up map projection. */
   if (GDSValid (gds) != 0) {
      preErrSprintf ("ERROR: Grid Definition Section was not Valid.\n");
      return -1;
   }
   SetMapParamGDS (&map, gds);

   InitMapIni (&mapIni);
   if (mapIniFile != NULL) {
      if ((fp = fopen (mapIniFile, "rt")) == NULL) {
         errSprintf ("Couldn't open %s for read\n", mapIniFile);
         FreeMapIni (&mapIni);
         return -1;
      }
      if (ParseMapIniFile (&mapIni, mapIniOptions, fp) != 0) {
         FreeMapIni (&mapIni);
         return 0;
      }
      fclose (fp);
   } else {
      /* Set default background color. */
      mapIni.all.bg.f_null = 1;
      mapIni.all.bg.r = 255;
      mapIni.all.bg.g = 255;
      mapIni.all.bg.b = 255;
   }

   /* Set defaults for zoom. */
   if (mapIni.zoom.f_flag == 0) {
      if (map.f_latlon == 1) {
         mapIni.zoom.lat1 = map.lat1;
         mapIni.zoom.lon1 = map.lon1;
         mapIni.zoom.lat2 = map.latN;
         mapIni.zoom.lon2 = map.lonN;
      } else {
         myCxy2ll (&map, .5, .5, &(mapIni.zoom.lat1), &(mapIni.zoom.lon1));
         myCxy2ll (&map, gds->Nx + .5, gds->Ny + .5, &(mapIni.zoom.lat2),
                   &(mapIni.zoom.lon2));
#ifdef TESTING
         myCxy2ll (&map, .5, .5, &lat, &lon);
         printf ("%f %f\n", lat, lon);
         mapIni.zoom.lat1 = mapIni.zoom.lat2 = lat;
         mapIni.zoom.lon1 = mapIni.zoom.lon2 = lon;
         myCxy2ll (&map, .5, gds->Ny + .5, &lat, &lon);
         printf ("%f %f\n", lat, lon);
         if (lat < mapIni.zoom.lat1)
            mapIni.zoom.lat1 = lat;
         if (lat > mapIni.zoom.lat2)
            mapIni.zoom.lat2 = lat;
         if (lon < mapIni.zoom.lon1)
            mapIni.zoom.lon1 = lon;
         if (lon > mapIni.zoom.lon2)
            mapIni.zoom.lon2 = lon;
         myCxy2ll (&map, gds->Nx + .5, gds->Ny + .5, &lat, &lon);
         printf ("%f %f\n", lat, lon);
         if (lat < mapIni.zoom.lat1)
            mapIni.zoom.lat1 = lat;
         if (lat > mapIni.zoom.lat2)
            mapIni.zoom.lat2 = lat;
         if (lon < mapIni.zoom.lon1)
            mapIni.zoom.lon1 = lon;
         if (lon > mapIni.zoom.lon2)
            mapIni.zoom.lon2 = lon;
         myCxy2ll (&map, gds->Nx + .5, .5, &lat, &lon);
         printf ("%f %f\n", lat, lon);
         if (lat < mapIni.zoom.lat1)
            mapIni.zoom.lat1 = lat;
         if (lat > mapIni.zoom.lat2)
            mapIni.zoom.lat2 = lat;
         if (lon < mapIni.zoom.lon1)
            mapIni.zoom.lon1 = lon;
         if (lon > mapIni.zoom.lon2)
            mapIni.zoom.lon2 = lon;
         printf ("%f %f\n", lat, lon);
         printf ("%f %f %f %f\n", mapIni.zoom.lat1, mapIni.zoom.lon1,
                 mapIni.zoom.lat2, mapIni.zoom.lon2);
#endif
      }
      mapIni.zoom.f_flag = 15;
   }

   /* Set defaults for projection section. */
   if ((mapIni.proj.f_flag1 != 31) || (mapIni.proj.f_flag2 != 31)) {
      mapIni.proj.type = gds->projType;
      mapIni.proj.minEarth = gds->minEarth;
      mapIni.proj.majEarth = gds->majEarth;
      mapIni.proj.lat1 = gds->lat1;
      mapIni.proj.lon1 = gds->lon1;
      mapIni.proj.f_flag1 = 31;
      mapIni.proj.mesh = gds->Dx;
      orientLon = gds->orientLon;
      if (orientLon > 180) {
         orientLon -= 360;
      }
      if (orientLon < -180) {
         orientLon += 360;
      }
      mapIni.proj.orientLon = orientLon;
      mapIni.proj.meshLat = gds->meshLat;
      mapIni.proj.scaleLat1 = gds->scaleLat1;
      mapIni.proj.scaleLat2 = gds->scaleLat2;
      mapIni.proj.f_flag2 = 31;
   }

   if (mapIni.all.numLayer == 0) {
      mapIni.all.numLayer = 1;
      mapIni.all.layers = (layerType *) malloc (mapIni.all.numLayer *
                                                sizeof (layerType));
      InitLayer (&(mapIni.all.layers[0]));
      mapIni.all.layers[0].type = GRID;
      mapIni.all.layers[0].shpType = MEMORY;
      mapIni.all.layers[0].ramp.numColors = 0;
      mapIni.all.layers[0].ramp.colors = NULL;
      mapIni.all.layers[0].ramp.numLab = 0;
      mapIni.all.layers[0].ramp.labRay = NULL;
      mapIni.all.layers[0].ramp.labJust = NULL;
      mapIni.all.layers[0].ramp.label = NULL;
      mapIni.all.layers[0].ramp.f_missing = 0;
      mapIni.all.layers[0].ramp.thick = 0;
   }
   for (i = 0; i < mapIni.all.numLayer; i++) {
      if (mapIni.all.layers[i].shpType == MEMORY) {
         mapIni.all.layers[i].gridData = grib_Data;
         mapIni.all.layers[i].gridNx = gds->Nx;
         mapIni.all.layers[i].gridNy = gds->Ny;
         mapIni.all.layers[i].gridProj.type = gds->projType;
         mapIni.all.layers[i].gridProj.minEarth = gds->minEarth;
         mapIni.all.layers[i].gridProj.majEarth = gds->majEarth;
         mapIni.all.layers[i].gridProj.lat1 = gds->lat1;
         mapIni.all.layers[i].gridProj.lon1 = gds->lon1;
         mapIni.all.layers[i].gridProj.f_flag1 = 31;
         mapIni.all.layers[i].gridProj.mesh = gds->Dx;
         orientLon = gds->orientLon;
         if (orientLon > 180) {
            orientLon -= 360;
         }
         if (orientLon < -180) {
            orientLon += 360;
         }
         mapIni.all.layers[i].gridProj.orientLon = orientLon;
         mapIni.all.layers[i].gridProj.meshLat = gds->meshLat;
         mapIni.all.layers[i].gridProj.scaleLat1 = gds->scaleLat1;
         mapIni.all.layers[i].gridProj.scaleLat2 = gds->scaleLat2;
         mapIni.all.layers[i].gridProj.f_flag2 = 31;
         if (mapIni.all.layers[i].ramp.numColors == 0) {
            SetGridRamp (&(mapIni.all.layers[i]), Min, Max, f_missing,
                         missing);
         } else {
            if (f_missing) {
               mapIni.all.layers[i].ramp.missValue = missing;
               mapIni.all.layers[i].ramp.f_missing = f_missing;
            }
         }
      }
   }

   /* Set defaults for output. */
   if (mapIni.out.f_flag != 3) {
      mapIni.out.X_Size = 520;
      mapIni.out.Y_Size = 420;
      mapIni.out.f_flag = 3;
   }

   if (mapIni.out.numOutputs == 0) {
      mapIni.out.numOutputs = 1;
      mapIni.out.outputs = (outputType *) malloc (mapIni.out.numOutputs *
                                                  sizeof (outputType));
      mapIni.out.outputs[0].numActive = 1;
      mapIni.out.outputs[0].active =
            (int *) malloc (mapIni.out.outputs[0].numActive * sizeof (int));
      mapIni.out.outputs[0].active[0] = 1;
      mapIni.out.outputs[0].filename = NULL;
   }

   for (i = 0; i < mapIni.out.numOutputs; i++) {
      if (mapIni.out.outputs[i].filename == NULL) {
         mapIni.out.outputs[i].filename =
               (char *) malloc (nameLen + 1 * sizeof (char));
         strncpy (mapIni.out.outputs[i].filename, Filename, nameLen - 3);
         strncpy (mapIni.out.outputs[i].filename + nameLen - 3, "png", 3);
         mapIni.out.outputs[i].filename[nameLen] = '\0';
      }
   }

   if (ValidateMapIni (&mapIni) != 0) {
      printf ("MapINI was invalid \n");
      FreeMapIni (&mapIni);
      return 0;
   }
#ifdef DEBUG
   printf ("Before ControlDraw. %f\n", clock () / (double) (CLOCKS_PER_SEC));
#endif
   ControlDraw (&mapIni);
#ifdef DEBUG
   printf ("after ControlDraw. %f\n", clock () / (double) (CLOCKS_PER_SEC));
#endif

   FreeMapIni (&mapIni);
   return 0;
}
Example #9
0
/*****************************************************************************
 * GRIB2Inventory() -- Review 12/2002
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *   Fills out an inventory structure for each GRIB message in a GRIB file,
 * without calling the FORTRAN routines to unpack the message.  It returns
 * the number of messages it found, or a negative number signifying an error.
 *
 * ARGUMENTS
 * filename = File to do the inventory of. (Input)
 *      Inv = The resultant array of inventories. (Output)
 *   LenInv = Length of the Array Inv (Output)
 *   numMsg = # of messages to inventory (0 = all, 1 = just first) (In)
 *   msgNum = MsgNum to start with, MsgNum of last message (Input/Output)
 *
 * FILES/DATABASES:
 *    Opens a GRIB2 file for reading given its filename.
 *
 * RETURNS: int (could use errSprintf())
 * +# = number of GRIB2 messages in the file.
 * -1 = Problems opening file for read.
 * -2 = Problems in section 0
 * -3 = Ran out of file.
 * -4 = Problems Reading in section 1
 * -5 = Problems Reading in section 2 or 3
 * -6 = Problems Reading in section 3
 * -7 = Problems Reading in section 4
 * -8 = Problems Parsing section 4.
 * -9 = Problems Reading in section 5
 * -10 = Problems Reading in section 6
 * -11 = Problems Reading in section 7
 * -12 = Problems inventory'ing a GRIB1 record
 * -13 = Problems inventory'ing a TDLP record
 *
 * HISTORY
 *   9/2002 Arthur Taylor (MDL/RSIS): Created.
 *  11/2002 AAT: Revised.
 *  12/2002 (TK,AC,TB,&MS): Code Review.
 *   3/2003 AAT: Corrected some satellite type mistakes.
 *   3/2003 AAT: Implemented multiple grid inventories in the same GRIB2
 *          message.
 *   4/2003 AAT: Started adding GRIB1 support
 *   6/2003 Matthew T. Kallio ([email protected]):
 *          "wmo" dimension increased to WMO_HEADER_LEN + 1 (for '\0' char)
 *   7/2003 AAT: Added numMsg so we can quickly find the reference time for
 *          a file by inventorying just the first message.
 *   8/2003 AAT: Adjusted use of GRIB_LIMIT to only affect the first message
 *          after we know we have a GRIB file, we don't want "trailing" bytes
 *          to break the program.
 *   8/2003 AAT: switched fileLen to only be computed for an error message.
 *   8/2003 AAT: curTot no longer serves a purpose.
 *   5/2004 AAT: Added a check for section number 2..8 for the repeated
 *          section (otherwise error)
 *  10/2004 AAT: Added ability to inventory TDLP records.
 *
 * NOTES
 *****************************************************************************
 */
int GRIB2Inventory (DataSource &fp, inventoryType **Inv, uInt4 *LenInv,
                    int numMsg, int *MsgNum)
{
   //FileDataSource fp (filename);            /* The opened GRIB2 file. */
   sInt4 offset = 0;    /* Where we are in the file. */
   sInt4 msgNum;        /* Which GRIB2 message we are on. */
   uInt4 gribLen;       /* Length of the current GRIB message. */
   uInt4 secLen;        /* Length of current section. */
   sChar sectNum;       /* Which section we are reading. */
   char *buff;          /* Holds the info between records. */
   uInt4 buffLen;       /* Length of info between records. */
   sInt4 sect0[SECT0LEN_WORD]; /* Holds the current Section 0. */
   char *buffer = NULL; /* Holds a given section. */
   uInt4 bufferLen = 0; /* Size of buffer. */
   inventoryType *inv;  /* Local ptr to Inv to reduce ptr confusion. */
   inventoryType *lastInv; /* Used to point to last inventory record when
                            * there are multiple grids in the same message. */
   wordType word;       /* Used to parse the prodType out of Sect 0. */
   int ans;             /* The return error code of ReadSect0. */
   char *msg;           /* Used to pop messages off the error Stack. */
   int version;         /* Which version of GRIB is in this message. */
   uChar prodType;      /* Which GRIB2 type of product, 0 is meteo, 1 is
                         * hydro, 2 is land, 3 is space, 10 is oceanographic. 
                         */
   int grib_limit;      /* How many bytes to look for before the first "GRIB" 
                         * in the file.  If not found, is not a GRIB file. */
   int c;               /* Determine if end of the file without fileLen. */
   sInt4 fileLen;       /* Length of the GRIB2 file. */
   unsigned short int center, subcenter; /* Who produced it. */
   // char *ptr;           /* used to find the file extension. */

   grib_limit = GRIB_LIMIT;
	 /*
   if (filename != NULL) {
      //if ((fp = fopen (filename, "rb")) == NULL) {
      //   errSprintf ("ERROR: Problems opening %s for read.", filename);
      //   return -1;
      //}
		  //fp = FileDataSource(filename);
      ptr = strrchr (filename, '.');
      if (ptr != NULL) {
         if (strcmp (ptr, ".tar") == 0) {
            grib_limit = 5000;
         }
      }
   } else {
      //fp = stdin; // TODO!!
   }
	 */
   msgNum = *MsgNum;

   buff = NULL;
   buffLen = 0;
   while ((c = fp.DataSourceFgetc()) != EOF) {
		 fp.DataSourceUngetc(c);
      // ungetc (c, fp);
      /* msgNum++ done first so any error messages range from 1..n, instead
       * of 0.. n-1. Note msgNum should end up as n not (n-1) */
      msgNum++;
/* Used when testing inventory of large TDLPack files. */
/*
#ifdef DEBUG
      myAssert (msgNum < 32500L);
      if (msgNum % 10 == 0) {
         printf ("%ld :: %f\n", msgNum, clock () / (double) CLOCKS_PER_SEC);
      }
#endif
*/
      /* Make it so the second, third, etc messages have no limit to finding
       * the "GRIB" keyword. */
      if (msgNum > 1) {
         grib_limit = -1;
      }
      /* Read in the wmo header and sect0. */
      if (ReadSECT0 (fp, &buff, &buffLen, grib_limit, sect0, &gribLen,
                     &version) < 0) {
         if (msgNum == 1) {
            /* Handle case where we couldn't find 'GRIB' in the message. */
            preErrSprintf ("Inside GRIB2Inventory, Message # %d\n", msgNum);
            free (buffer);
            free (buff);
            //fclose (fp);
            return -2;
         } else {
            /* Handle case where there are trailing bytes. */
            msg = errSprintf (NULL);
            printf ("Warning: Inside GRIB2Inventory, Message # %d\n",
                    msgNum);
            printf ("%s", msg);
            free (msg);
            /* find out how big the file is. */
            fp.DataSourceFseek (0L, SEEK_END);
            fileLen = static_cast<int>(fp.DataSourceFtell());
            /* fseek (fp, 0L, SEEK_SET); */
            printf ("There were %d trailing bytes in the file.\n",
                    fileLen - offset);
            free (buffer);
            free (buff);
            //fclose (fp);
            return msgNum;
         }
      }

      /* Make room for this GRIB message in the inventory list. */
      *LenInv = *LenInv + 1;
      *Inv = (inventoryType *) realloc ((void *) *Inv,
                                        *LenInv * sizeof (inventoryType));
      inv = *Inv + (*LenInv - 1);

      /* Start parsing the message. */
      inv->GribVersion = version;
      inv->msgNum = msgNum;
      inv->subgNum = 0;
      inv->start = offset;
      inv->element = NULL;
      inv->comment = NULL;
      inv->unitName = NULL;
      inv->shortFstLevel = NULL;
      inv->longFstLevel = NULL;

      if (version == 1) {
         if (GRIB1_Inventory (fp, gribLen, inv) != 0) {
            preErrSprintf ("Inside GRIB2Inventory \n");
            free (buffer);
            free (buff);
            //fclose (fp);
            return -12;
         }
      } else if (version == -1) {
         if (TDLP_Inventory (fp, gribLen, inv) != 0) {
            preErrSprintf ("Inside GRIB2Inventory \n");
            free (buffer);
            free (buff);
            //fclose (fp);
            return -13;
         }
      } else {
         word.li = sect0[1];
         prodType = word.buffer[2];

         /* Read section 1 into buffer. */
         sectNum = 1;
         if (GRIB2SectToBuffer (fp, gribLen, &sectNum, &secLen, &bufferLen,
                                &buffer) != 0) {
            errSprintf ("ERROR: Problems with section 1\n");
            free (buffer);
            free (buff);
            //fclose (fp);
            return -4;
         }
         /* Parse the interesting data out of sect 1. */
         InventoryParseTime (buffer + 13 - 5, &(inv->refTime));
         MEMCPY_BIG (&center, buffer + 6 - 5, sizeof (short int));
         MEMCPY_BIG (&subcenter, buffer + 8 - 5, sizeof (short int));

         sectNum = 2;
         do {
            /* Look at sections 2 to 7 */
            if ((ans = GRIB2Inventory2to7 (sectNum, fp, gribLen, &bufferLen,
                                           &buffer, inv, prodType, center,
                                           subcenter)) != 0) {
               //fclose (fp);
               free (buffer);
               free (buff);
               return ans;
            }
            /* Try to read section 8. If it is "7777" = 926365495 regardless
             * of endian'ness then we have a simple message, otherwise it is
             * complex, and we need to read more. */
            if (FREAD_BIG (&secLen, sizeof (sInt4), 1, fp) != 1) {
               errSprintf ("ERROR: Ran out of file looking for Sect 8.\n");
               free (buffer);
               free (buff);
               // fclose (fp);
               return -4;
            }
            if (secLen == 926365495L) {
               sectNum = 8;
            } else {
               if (fp.DataSourceFread (&sectNum, sizeof (char), 1) != 1) {
                  errSprintf ("ERROR: Ran out of file looking for "
                              "subMessage.\n");
                  free (buffer);
                  free (buff);
                  //fclose (fp);
                  return -4;
               }
               if ((sectNum < 2) || (sectNum > 7)) {
                  errSprintf ("ERROR (GRIB2Inventory): Couldn't find the end"
                              " of message\n");
                  errSprintf ("and it doesn't appear to repeat sections.\n");
                  errSprintf ("so it is probably an ASCII / binary bug\n");
                  free (buffer);
                  free (buff);
                  //fclose (fp);
                  return -4;
               }
               fp.DataSourceFseek (-5, SEEK_CUR);
               /* Make room for the next part of this GRIB message in the
                * inventory list.  This is for when we have sub-grids. */
               *LenInv = *LenInv + 1;
               *Inv = (inventoryType *) realloc ((void *) *Inv,
                                                 *LenInv *
                                                 sizeof (inventoryType));
               inv = *Inv + (*LenInv - 1);
               lastInv = *Inv + (*LenInv - 2);

               inv->GribVersion = version;
               inv->msgNum = msgNum;
               inv->subgNum = lastInv->subgNum + 1;
               inv->start = offset;
               inv->element = NULL;
               inv->comment = NULL;
               inv->unitName = NULL;
               inv->shortFstLevel = NULL;
               inv->longFstLevel = NULL;

               word.li = sect0[1];
               prodType = word.buffer[2];
               inv->refTime = lastInv->refTime;
            }
         } while (sectNum != 8);
      }

      /* added to inventory either first msgNum messages, or all messages */
      if (numMsg == msgNum) {
         break;
      }
      /* Continue on to the next GRIB2 message. */
      if (version == -1) {
         /* TDLPack uses 4 bytes for FORTRAN record size, then another 8
          * bytes for the size of the record (so FORTRAN can see it), then
          * the data rounded up to an 8 byte boundary, then a trailing 4
          * bytes for a final FORTRAN record size.  However it only stores
          * in_ the gribLen the non-rounded amount, so we need to take care
          * of the rounding, and the trailing 4 bytes here. */
         offset += buffLen + ((sInt4) ceil (gribLen / 8.0)) * 8 + 4;
      } else {
         offset += buffLen + gribLen;
      }
      fp.DataSourceFseek (offset, SEEK_SET);
   }
   free (buffer);
   free (buff);
   //fclose (fp);
   *MsgNum = msgNum;
   return msgNum;
}
Example #10
0
/*****************************************************************************
 * GRIB2Inventory2to7() --
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *   Inventories sections 3 to 7, filling out the inv record with the data in
 * section 4.  (Note: No Call to FORTRAN routines here).
 *
 * ARGUMENTS
 *   sectNum = Which section we are currently reading. (Input)
 *        fp = An opened file pointer to the file to the inventory of (In/Out)
 *   gribLen = The total length of the grib message. (Input)
 *   buffLen = length of buffer. (Input)
 *    buffer = Holds a given section. (Input)
 *       inv = The current inventory record to fill out. (Output)
 *  prodType = The GRIB2 type of product: 0 is meteo product, 1 is hydro,
 *             2 is land, 3 is space, 10 is oceanographic. (Input)
 *    center = Who produced it (Input)
 * subcenter = A sub group of center that actually produced it (Input)
 *
 * FILES/DATABASES:
 *
 * RETURNS: int (could use errSprintf())
 *  0 = "Ok"
 * -5 = Problems Reading in section 2 or 3
 * -6 = Problems Reading in section 3
 * -7 = Problems Reading in section 4
 * -8 = Problems Parsing section 4.
 * -9 = Problems Reading in section 5
 * -10 = Problems Reading in section 6
 * -11 = Problems Reading in section 7
 *
 * HISTORY
 *   3/2003 Arthur Taylor (MDL/RSIS): Created.
 *   4/2003 AAT: Modified to not have prodType, cat, subcat, templat in
 *          inventoryType structure.
 *   8/2003 AAT: curTot no longer serves a purpose.
 *   1/2004 AAT: Added center/subcenter.
 *
 * NOTES
 *****************************************************************************
 */
static int GRIB2Inventory2to7 (sChar sectNum, DataSource &fp, sInt4 gribLen,
                               uInt4 *buffLen, char **buffer,
                               inventoryType *inv, uChar prodType,
                               unsigned short int center,
                               unsigned short int subcenter)
{
   uInt4 secLen;        /* The length of the current section. */
   sInt4 foreTime;      /* forecast time (NDFD treats as "projection") */
   uChar foreTimeUnit;  /* The time unit of the "forecast time". */
   /* char *element; *//* Holds the name of the current variable. */
   /* char *comment; *//* Holds more comments about current variable. */
   /* char *unitName; *//* Holds the name of the unit [K] [%] .. etc */
   int convert;         /* Enum type of unit conversions (metaname.c),
                         * Conversion method for this variable's unit. */
   uChar cat;           /* General category of Meteo Product. */
   unsigned short int templat; /* The section 4 template number. */
   uChar subcat;        /* Specific subcategory of Product. */
   uChar fstSurfType;   /* Type of the first fixed surface. */
   double fstSurfValue; /* Value of first fixed surface. */
   sInt4 value;         /* The scaled value from GRIB2 file. */
   sChar factor;        /* The scaled factor from GRIB2 file */
   sChar scale;         /* Surface scale as opposed to probability factor. */
   uChar sndSurfType;   /* Type of the second fixed surface. */
   double sndSurfValue; /* Value of second fixed surface. */
   sChar f_sndValue;    /* flag if SndValue is valid. */
   uChar timeRangeUnit;
   sInt4 lenTime;       /* Used by parseTime to tell difference between 8hr
                         * average and 1hr average ozone. */
   uChar genID;         /* The Generating process ID (used for GFS MOS) */
   uChar probType;      /* The probability type */
   double lowerProb;    /* The lower limit on probability forecast if
                         * template 4.5 or 4.9 */
   double upperProb;    /* The upper limit on probability forecast if
                         * template 4.5 or 4.9 */
   uChar timeIncrType;
   sChar percentile = 0;

   if ((sectNum == 2) || (sectNum == 3)) {
      /* Jump past section (2 or 3). */
      sectNum = -1;
      if (GRIB2SectJump (fp, gribLen, &sectNum, &secLen) != 0) {
         errSprintf ("ERROR: Problems Jumping past section 2 || 3\n");
         return -6;
      }
      if ((sectNum != 2) && (sectNum != 3)) {
         errSprintf ("ERROR: Section 2 or 3 mislabeled\n");
         return -5;
      } else if (sectNum == 2) {
         /* Jump past section 3. */
         sectNum = 3;
         if (GRIB2SectJump (fp, gribLen, &sectNum, &secLen) != 0) {
            errSprintf ("ERROR: Problems Jumping past section 3\n");
            return -6;
         }
      }
   }
   /* Read section 4 into buffer. */
   sectNum = 4;
   if (GRIB2SectToBuffer (fp, gribLen, &sectNum, &secLen, buffLen,
                          buffer) != 0) {
      errSprintf ("ERROR: Problems with section 4\n");
      return -7;
   }
/*
enum { GS4_ANALYSIS, GS4_ENSEMBLE, GS4_DERIVED, GS4_PROBABIL_PNT = 5,
   GS4_STATISTIC = 8, GS4_PROBABIL_TIME = 9, GS4_PERCENTILE = 10,
   GS4_RADAR = 20, GS4_SATELLITE = 30
};
*/
   /* Parse the interesting data out of sect 4. */
   MEMCPY_BIG (&templat, *buffer + 8 - 5, sizeof (short int));
   if ((templat != GS4_ANALYSIS) && (templat != GS4_ENSEMBLE)
       && (templat != GS4_DERIVED)
       && (templat != GS4_PROBABIL_PNT) && (templat != GS4_STATISTIC)
       && (templat != GS4_PROBABIL_TIME) && (templat != GS4_PERCENTILE)
       && (templat != GS4_ENSEMBLE_STAT)
       && (templat != GS4_RADAR) && (templat != GS4_SATELLITE)
       && (templat != GS4_DERIVED_INTERVAL)) {
      errSprintf ("This was only designed for templates 0, 1, 2, 5, 8, 9, "
                  "10, 11, 12, 20, 30\n");
      return -8;
   }
   cat = (*buffer)[10 - 5];
   subcat = (*buffer)[11 - 5];
   genID = 0;
   probType = 0;
   lowerProb = 0;
   upperProb = 0;
   if ((templat == GS4_RADAR) || (templat == GS4_SATELLITE) ||
       (templat == 254)) {
      inv->foreSec = 0;
      inv->validTime = inv->refTime;
      timeIncrType = 255;
      timeRangeUnit = 255;
      lenTime = 0;
   } else {
      genID = (*buffer)[14 - 5];
      /* Compute forecast time. */
      foreTimeUnit = (*buffer)[18 - 5];
      MEMCPY_BIG (&foreTime, *buffer + 19 - 5, sizeof (sInt4));
      if (ParseSect4Time2sec (foreTime, foreTimeUnit, &(inv->foreSec)) != 0) {
         errSprintf ("unable to convert TimeUnit: %d \n", foreTimeUnit);
         return -8;
      }
      /* Compute valid time. */
      inv->validTime = inv->refTime + inv->foreSec;
      timeIncrType = 255;
      timeRangeUnit = 1;
      lenTime = (sInt4) (inv->foreSec / 3600);
      switch (templat) {
         case GS4_PROBABIL_PNT: /* 4.5 */
            probType = (*buffer)[37 - 5];
            factor = (sChar) (*buffer)[38 - 5];
            MEMCPY_BIG (&value, *buffer + 39 - 5, sizeof (sInt4));
            lowerProb = value * pow (10.0, -1 * factor);
            factor = (sChar) (*buffer)[43 - 5];
            MEMCPY_BIG (&value, *buffer + 44 - 5, sizeof (sInt4));
            upperProb = value * pow (10.0, -1 * factor);
            break;
         case GS4_DERIVED_INTERVAL: /* 4.12 */
            if (InventoryParseTime (*buffer + 37 - 5, &(inv->validTime)) != 0) {
               printf ("Warning: Investigate Template 4.12 bytes 37-43\n");
               inv->validTime = inv->refTime + inv->foreSec;
            }
            timeIncrType = (*buffer)[50 - 5];
            timeRangeUnit = (*buffer)[51 - 5];
            MEMCPY_BIG (&lenTime, *buffer + 52 - 5, sizeof (sInt4));
/* If lenTime == missing (2^32 -1) we might do something, but not with 255.*/
/*
            if (lenTime == 255) {
               lenTime = (inv->validTime -
                          (inv->refTime + inv->foreSec)) / 3600;
            }
*/
            break;
         case GS4_PERCENTILE: /* 4.10 */
            percentile = (*buffer)[35 - 5];
            if (InventoryParseTime (*buffer + 36 - 5, &(inv->validTime)) != 0) {
               printf ("Warning: Investigate Template 4.10 bytes 36-42\n");
               inv->validTime = inv->refTime + inv->foreSec;
            }
            timeIncrType = (*buffer)[49 - 5];
            timeRangeUnit = (*buffer)[50 - 5];
            MEMCPY_BIG (&lenTime, *buffer + 51 - 5, sizeof (sInt4));
/* If lenTime == missing (2^32 -1) we might do something, but not with 255.*/
/*
            if (lenTime == 255) {
               lenTime = (inv->validTime -
                          (inv->refTime + inv->foreSec)) / 3600;
            }
*/
            break;
         case GS4_STATISTIC: /* 4.8 */
            if (InventoryParseTime (*buffer + 35 - 5, &(inv->validTime)) != 0) {
               printf ("Warning: Investigate Template 4.8 bytes 35-41\n");
               inv->validTime = inv->refTime + inv->foreSec;
            }
            timeIncrType = (*buffer)[48 - 5];
            timeRangeUnit = (*buffer)[49 - 5];
            MEMCPY_BIG (&lenTime, *buffer + 50 - 5, sizeof (sInt4));
/* If lenTime == missing (2^32 -1) we might do something, but not with 255.*/
/*
            if (lenTime == 255) {
               lenTime = (inv->validTime -
                          (inv->refTime + inv->foreSec)) / 3600;
            }
*/
            break;
         case GS4_ENSEMBLE_STAT: /* 4.11 */
            if (InventoryParseTime (*buffer + 38 - 5, &(inv->validTime)) != 0) {
               printf ("Warning: Investigate Template 4.11 bytes 38-44\n");
               inv->validTime = inv->refTime + inv->foreSec;
            }
            timeIncrType = (*buffer)[51 - 5];
            timeRangeUnit = (*buffer)[52 - 5];
            MEMCPY_BIG (&lenTime, *buffer + 53 - 5, sizeof (sInt4));
/* If lenTime == missing (2^32 -1) we might do something, but not with 255.*/
/*
            if (lenTime == 255) {
               lenTime = (inv->validTime -
                          (inv->refTime + inv->foreSec)) / 3600;
            }
*/
            break;
         case GS4_PROBABIL_TIME: /* 4.9 */
            probType = (*buffer)[37 - 5];
            if ((uChar) (*buffer)[38 - 5] > 128) {
               factor = 128 - (uChar) (*buffer)[38 - 5];
            } else {
               factor = (*buffer)[38 - 5];
            }
            MEMCPY_BIG (&value, *buffer + 39 - 5, sizeof (sInt4));
            lowerProb = value * pow (10.0, -1 * factor);

            if ((uChar) (*buffer)[43 - 5] > 128) {
               factor = 128 - (uChar) (*buffer)[43 - 5];
            } else {
               factor = (*buffer)[43 - 5];
            }
            MEMCPY_BIG (&value, *buffer + 44 - 5, sizeof (sInt4));
            upperProb = value * pow (10.0, -1 * factor);

            if (InventoryParseTime (*buffer + 48 - 5, &(inv->validTime)) != 0) {
               printf ("Warning: Investigate Template 4.9 bytes 48-54\n");
               inv->validTime = inv->refTime + inv->foreSec;
            }
            timeIncrType = (*buffer)[61 - 5];
            timeRangeUnit = (*buffer)[62 - 5];
            MEMCPY_BIG (&lenTime, *buffer + 63 - 5, sizeof (sInt4));
/* If lenTime == missing (2^32 -1) we might do something, but not with 255.*/
/*
            if (lenTime == 255) {
               lenTime = (inv->validTime -
                          (inv->refTime + inv->foreSec)) / 3600;
            }
*/
            break;
      }
   }

   if (timeRangeUnit == 255) {
      timeRangeUnit = 1;
      lenTime = (sInt4) ((inv->validTime - inv->foreSec - inv->refTime) /
                         3600);
   }
/*   myAssert (timeRangeUnit == 1);*/
   /* Try to convert lenTime to hourly. */
   if (timeRangeUnit == 0) {
      lenTime = (sInt4) (lenTime / 60.);
      /*timeRangeUnit = 1;*/
   } else if (timeRangeUnit == 1) {
   } else if (timeRangeUnit == 2) {
      lenTime = lenTime * 24;
      /*timeRangeUnit = 1;*/
   } else if (timeRangeUnit == 10) {
      lenTime = lenTime * 3;
      /*timeRangeUnit = 1;*/
   } else if (timeRangeUnit == 11) {
      lenTime = lenTime * 6;
      /*timeRangeUnit = 1;*/
   } else if (timeRangeUnit == 12) {
      lenTime = lenTime * 12;
      /*timeRangeUnit = 1;*/
   } else if (timeRangeUnit == 13) {
      lenTime = (sInt4) (lenTime / 3600.);
      /*timeRangeUnit = 1;*/
   } else {
      printf ("Can't handle this timeRangeUnit\n");
      //myAssert (timeRangeUnit == 1);
      return -8;
   }
   if (lenTime == GRIB2MISSING_s4) {
      lenTime = 0;
   }
   /* Find out what the name of this variable is. */
   ParseElemName (center, subcenter, prodType, templat, cat, subcat,
                  lenTime, timeIncrType, genID, probType, lowerProb,
                  upperProb, &(inv->element), &(inv->comment),
                  &(inv->unitName), &convert, percentile);
/*
   if (strcmp (element, "") == 0) {
      mallocSprintf (&(inv->element), "unknown");
      mallocSprintf (&(inv->unitName), "[%s]", unitName);
      if (strcmp (comment, "unknown") == 0) {
         mallocSprintf (&(inv->comment), "(prodType %d, cat %d, subcat %d)"
                        " [%s]", prodType, cat, subcat, unitName);
      } else {
         mallocSprintf (&(inv->comment), "%s [%s]", comment, unitName);
      }
   } else {
      if (IsData_MOS (center, subcenter)) {
         * See : http://www.nco.ncep.noaa.gov/pmb/docs/on388/tablea.html *
         if (genID == 96) {
            inv->element = (char *) malloc ((1 + 7 + strlen (element))
                                            * sizeof (char));
            sprintf (inv->element, "MOSGFS-%s", element);
         } else {
            inv->element = (char *) malloc ((1 + 4 + strlen (element))
                                            * sizeof (char));
            sprintf (inv->element, "MOS-%s", element);
         }
      } else {
         inv->element = (char *) malloc ((1 + strlen (element))
                                         * sizeof (char));
         strcpy (inv->element, element);
      }
      mallocSprintf (&(inv->unitName), "[%s]", unitName);
      mallocSprintf (&(inv->comment), "%s [%s]", comment, unitName);
*
      inv->unitName = (char *) malloc ((1 + 2 + strlen (unitName))
                                       * sizeof (char));
      sprintf (inv->unitName, "[%s]", unitName);
      inv->comment = (char *) malloc ((1 + 3 + strlen (unitName) + strlen (comment))
                                      * sizeof (char));
      sprintf (inv->comment, "%s [%s]", comment, unitName);
*
   }
*/

   if ((templat == GS4_RADAR) || (templat == GS4_SATELLITE)
       || (templat == 254) || (templat == 1000) || (templat == 1001)
       || (templat == 1002)) {
      reallocSprintf (&(inv->shortFstLevel), "0 undefined");
      reallocSprintf (&(inv->longFstLevel), "0.000[-] undefined ()");
   } else {
      fstSurfType = (*buffer)[23 - 5];
      scale = (*buffer)[24 - 5];
      MEMCPY_BIG (&value, *buffer + 25 - 5, sizeof (sInt4));
      if ((value == GRIB2MISSING_s4) || (scale == GRIB2MISSING_s1)) {
         fstSurfValue = 0;
      } else {
         fstSurfValue = value * pow (10.0, (int) (-1 * scale));
      }
      sndSurfType = (*buffer)[29 - 5];
      scale = (*buffer)[30 - 5];
      MEMCPY_BIG (&value, *buffer + 31 - 5, sizeof (sInt4));
      if ((value == GRIB2MISSING_s4) || (scale == GRIB2MISSING_s1) ||
          (sndSurfType == GRIB2MISSING_u1)) {
         sndSurfValue = 0;
         f_sndValue = 0;
      } else {
         sndSurfValue = value * pow (10.0, -1 * scale);
         f_sndValue = 1;
      }

      ParseLevelName (center, subcenter, fstSurfType, fstSurfValue,
                      f_sndValue, sndSurfValue, &(inv->shortFstLevel),
                      &(inv->longFstLevel));
   }

   /* Jump past section 5. */
   sectNum = 5;
   if (GRIB2SectJump (fp, gribLen, &sectNum, &secLen) != 0) {
      errSprintf ("ERROR: Problems Jumping past section 5\n");
      return -9;
   }
   /* Jump past section 6. */
   sectNum = 6;
   if (GRIB2SectJump (fp, gribLen, &sectNum, &secLen) != 0) {
      errSprintf ("ERROR: Problems Jumping past section 6\n");
      return -10;
   }
   /* Jump past section 7. */
   sectNum = 7;
   if (GRIB2SectJump (fp, gribLen, &sectNum, &secLen) != 0) {
      errSprintf ("ERROR: Problems Jumping past section 7\n");
      return -11;
   }
   return 0;
}
Example #11
0
int GRIB2RefTime (char *filename, double *refTime)
{
   FileDataSource fp (filename);            /* The opened GRIB2 file. */
   sInt4 offset = 0;    /* Where we are in the file. */
   sInt4 msgNum;        /* Which GRIB2 message we are on. */
   uInt4 gribLen;       /* Length of the current GRIB message. */
   uInt4 secLen;        /* Length of current section. */
   sChar sectNum;       /* Which section we are reading. */
   char *buff;          /* Holds the info between records. */
   uInt4 buffLen;       /* Length of info between records. */
   sInt4 sect0[SECT0LEN_WORD]; /* Holds the current Section 0. */
   char *buffer = NULL; /* Holds a given section. */
   uInt4 bufferLen = 0; /* Size of buffer. */
   /* wordType word; */       /* Used to parse the prodType out of Sect 0. */
   int ans;             /* The return error code of ReadSect0. */
   char *msg;           /* Used to pop messages off the error Stack. */
   int version;         /* Which version of GRIB is in this message. */
   /* uChar prodType; */      /* Which GRIB2 type of product, 0 is meteo, 1 is
                         * hydro, 2 is land, 3 is space, 10 is oceanographic. 
                         */
   int grib_limit;      /* How many bytes to look for before the first "GRIB" 
                         * in the file.  If not found, is not a GRIB file. */
   int c;               /* Determine if end of the file without fileLen. */
   sInt4 fileLen;       /* Length of the GRIB2 file. */
   char *ptr;           /* used to find the file extension. */
   double refTime1;

   grib_limit = GRIB_LIMIT;
   if (filename != NULL) {
      //if ((fp = fopen (filename, "rb")) == NULL) {
      //   errSprintf ("ERROR: Problems opening %s for read.", filename);
      //   return -1;
      //}
		  //fp = DataSource(filename);
      ptr = strrchr (filename, '.');
      if (ptr != NULL) {
         if (strcmp (ptr, ".tar") == 0) {
            grib_limit = 5000;
         }
      }
   } else {
      // fp = stdin; // TODO!!
   }
   msgNum = 0;

   buff = NULL;
   buffLen = 0;
   while ((c = fp.DataSourceFgetc()) != EOF) {
		 fp.DataSourceUngetc(c);
      /* msgNum++ done first so any error messages range from 1..n, instead
       * of 0.. n-1. Note msgNum should end up as n not (n-1) */
      msgNum++;
      /* Make it so the second, third, etc messages have no limit to finding
       * the "GRIB" keyword. */
      if (msgNum > 1) {
         grib_limit = -1;
      }
      /* Read in the wmo header and sect0. */
      if ((ans = ReadSECT0 (fp, &buff, &buffLen, grib_limit, sect0, &gribLen,
                            &version)) < 0) {
         if (msgNum == 1) {
            /* Handle case where we couldn't find 'GRIB' in the message. */
            preErrSprintf ("Inside GRIB2RefTime, Message # %d\n", msgNum);
            free (buffer);
            free (buff);
            //fclose (fp);
            return -2;
         } else {
            /* Handle case where there are trailing bytes. */
            msg = errSprintf (NULL);
            printf ("Warning: Inside GRIB2RefTime, Message # %d\n", msgNum);
            printf ("%s", msg);
            free (msg);
            /* find out how big the file is. */
            fp.DataSourceFseek (0L, SEEK_END);
            fileLen = static_cast<int>(fp.DataSourceFtell());
            /* fseek (fp, 0L, SEEK_SET); */
            printf ("There were %d trailing bytes in the file.\n",
                    fileLen - offset);
            free (buffer);
            free (buff);
            //fclose (fp);
            return msgNum;
         }
      }

      if (version == 1) {
         if (GRIB1_RefTime (fp, gribLen, &(refTime1)) != 0) {
            preErrSprintf ("Inside GRIB1_RefTime\n");
            free (buffer);
            free (buff);
            //fclose (fp);
            return -12;
         }
      } else if (version == -1) {
         if (TDLP_RefTime (fp, gribLen, &(refTime1)) != 0) {
            preErrSprintf ("Inside TDLP_RefTime\n");
            free (buffer);
            free (buff);
            //fclose (fp);
            return -13;
         }
      } else {
          /* word.li = sect0[1]; */
         /* prodType = word.buffer[2]; */

         /* Read section 1 into buffer. */
         sectNum = 1;
         if (GRIB2SectToBuffer (fp, gribLen, &sectNum, &secLen, &bufferLen,
                                &buffer) != 0) {
            errSprintf ("ERROR: Problems with section 1\n");
            free (buffer);
            //fclose (fp);
            return -4;
         }
         /* Parse the interesting data out of sect 1. */
         InventoryParseTime (buffer + 13 - 5, &(refTime1));
      }
      if (msgNum == 1) {
         *refTime = refTime1;
      } else {
         if (*refTime > refTime1) {
            *refTime = refTime1;
         }
      }

      /* Continue on to the next GRIB2 message. */
      offset += gribLen + buffLen;
      fp.DataSourceFseek (offset, SEEK_SET);
   }
   free (buffer);
   free (buff);
   //fclose (fp);
   return 0;
}
Example #12
0
int ReadGrib2Record (DataSource &fp, sChar f_unit, double **Grib_Data,
                     uInt4 *grib_DataLen, grib_MetaData *meta,
                     IS_dataType *IS, int subgNum, double majEarth,
                     double minEarth, int simpVer, sInt4 *f_endMsg,
                     CPL_UNUSED LatLon *lwlf, CPL_UNUSED LatLon *uprt)
{
   sInt4 l3264b;        /* Number of bits in a sInt4.  Needed by FORTRAN
                         * unpack library to determine if system has a 4
                         * byte_ sInt4 or an 8 byte sInt4. */
   char *buff;          /* Holds the info between records. */
   uInt4 buffLen;       /* Length of info between records. */
   sInt4 sect0[SECT0LEN_WORD]; /* Holds the current Section 0. */
   uInt4 gribLen;       /* Length of the current GRIB message. */
   sInt4 nd5;           /* Size of grib message rounded up to the nearest
                         * sInt4. */
   char *c_ipack;       /* A char ptr to the message stored in IS->ipack */
   sInt4 local_ns[8];   /* Local copy of section lengths. */
   sInt4 nd2x3;         /* Total number of grid points. */
   short int table50;   /* Type of packing used. (See code table 5.0)
                         * (GS5_SIMPLE==0, GS5_CMPLX==2, GS5_CMPLXSEC==3) */
   sInt4 nidat;         /* Size of section 2 if it contains integer data. */
   sInt4 nrdat;         /* Size of section 2 if it contains float data. */
   sInt4 inew;          /* 1 if this is the first grid we are reading. 0 if
                         * this is the second or later grid from the same
                         * GRIB message. */
   sInt4 iclean = 0;    /* 0 embed the missing values, 1 don't. */
   int j;               /* Counter used to find the desired subgrid. */
   sInt4 kfildo = 5;    /* FORTRAN Unit number for diagnostic info. Ignored,
                         * unless library is compiled a particular way. */
   sInt4 ibitmap;       /* 0 means no bitmap returned, otherwise 1. */
   float xmissp;        /* The primary missing value.  If iclean = 0, this
                         * value is embeded in grid, otherwise it is the
                         * value returned from the GRIB message. */
   float xmisss;        /* The secondary missing value.  If iclean = 0, this
                         * value is embeded in grid, otherwise it is the
                         * value returned from the GRIB message. */
   sInt4 jer[UNPK_NUM_ERRORS * 2]; /* Any Error codes along with their *
                                    * severity levels generated using the *
                                    * unpack GRIB2 library. */
   sInt4 ndjer = UNPK_NUM_ERRORS; /* The number of rows in JER( ). */
   sInt4 kjer;          /* The actual number of errors returned in JER. */
   size_t i;            /* counter as we loop through jer. */
   double unitM, unitB; /* values in y = m x + b used for unit conversion. */
   char unitName[15];   /* Holds the string name of the current unit. */
   int unitLen;         /* String length of string name of current unit. */
   int version;         /* Which version of GRIB is in this message. */
   sInt4 cnt;           /* Used to help compact the weather table. */
   int x1, y1;          /* The original grid coordinates of the lower left
                         * corner of the subgrid. */
   int x2, y2;          /* The original grid coordinates of the upper right
                         * corner of the subgrid. */
   uChar f_subGrid;     /* True if we have a subgrid. */
   sInt4 Nx, Ny;        /* original size of the data. */

   /*
    * f_endMsg is 1 if in the past we either completed reading a message,
    * or we haven't read any messages.  In either case we need to read the
    * next message from file.
    * If f_endMsg is false, then there is more to read from IS->ipack, so we
    * don't want to throw it out, nor have to re-read ipack from disk.
    */
   l3264b = sizeof (sInt4) * 8;
   buff = NULL;
   buffLen = 0;
   if (*f_endMsg == 1) {
      if (ReadSECT0 (fp, &buff, &buffLen, -1, sect0, &gribLen, &version) < 0) {
         preErrSprintf ("Inside ReadGrib2Record\n");
         free (buff);
         return -1;
      }
      meta->GribVersion = version;
      if (version == 1) {
         if (ReadGrib1Record (fp, f_unit, Grib_Data, grib_DataLen, meta, IS,
                              sect0, gribLen, majEarth, minEarth) != 0) {
            preErrSprintf ("Problems with ReadGrib1Record called by "
                           "ReadGrib2Record\n");
            free (buff);
            return -1;
         }
         *f_endMsg = 1;
         free (buff);
         return 0;
      } else if (version == -1) {
         if (ReadTDLPRecord (fp, Grib_Data, grib_DataLen, meta, IS,
                             sect0, gribLen, majEarth, minEarth) != 0) {
            preErrSprintf ("Problems with ReadGrib1Record called by "
                           "ReadGrib2Record\n");
            free (buff);
            return -1;
         }
         free (buff);
         return 0;
      }

      /*
       * Make room for entire message, and read it in.
       */
      /* nd5 needs to be gribLen in (sInt4) units rounded up. */
      nd5 = (gribLen + 3) / 4;
      if (nd5 > IS->ipackLen) {
         IS->ipackLen = nd5;
         IS->ipack = (sInt4 *) realloc ((void *) (IS->ipack),
                                        (IS->ipackLen) * sizeof (sInt4));
      }
      c_ipack = (char *) IS->ipack;
      /* Init last sInt4 to 0, to make sure that the padded bytes are 0. */
      IS->ipack[nd5 - 1] = 0;
      /* Init first 4 sInt4 to sect0. */
      memcpy (c_ipack, sect0, SECT0LEN_WORD * 4);
      /* Read in the rest of the message. */
      if (fp.DataSourceFread (c_ipack + SECT0LEN_WORD * 4, sizeof (char),
                 (gribLen - SECT0LEN_WORD * 4)) != (gribLen - SECT0LEN_WORD * 4)) {
         errSprintf ("GribLen = %ld, SECT0Len_WORD = %d\n", gribLen,
                     SECT0LEN_WORD);
         errSprintf ("Ran out of file\n");
         free (buff);
         return -1;
      }

      /*
       * Make sure the arrays are large enough for call to unpacker library.
       */
      /* FindSectLen Does not want (ipack / c_ipack) word swapped, because
       * that would make it much more confusing to find bytes in c_ipack. */
      if (FindSectLen (c_ipack, gribLen, local_ns, &nd2x3, &table50) < 0) {
         preErrSprintf ("Inside ReadGrib2Record.. Calling FindSectLen\n");
         free (buff);
         return -2;
      }

      /* Make sure all 'is' arrays except ns[7] are MAX (IS.ns[] ,
       * local_ns[]). See note 1 for reason to exclude ns[7] from MAX (). */
      for (i = 0; i < 7; i++) {
         if (local_ns[i] > IS->ns[i]) {
            IS->ns[i] = local_ns[i];
            IS->is[i] = (sInt4 *) realloc ((void *) (IS->is[i]),
                                           IS->ns[i] * sizeof (sInt4));
         }
      }

      /* Allocate room for sect 2. If local_ns[2] = -1 there is no sect 2. */
      if (local_ns[2] == -1) {
         nidat = 10;
         nrdat = 10;
      } else {
         /*
          * See note 2) We have a section 2, so use:
          *     MAX (32 * local_ns[2],SECT2_INTSIZE)
          * and MAX (32 * local_ns[2],SECT2_FLOATSIZE)
          * for size of section 2 unpacked.
          */
         nidat = (32 * local_ns[2] < SECT2_INIT_SIZE) ? SECT2_INIT_SIZE :
               32 * local_ns[2];
         nrdat = nidat;
      }
      if (nidat > IS->nidat) {
         IS->nidat = nidat;
         IS->idat = (sInt4 *) realloc ((void *) IS->idat,
                                       IS->nidat * sizeof (sInt4));
      }
      if (nrdat > IS->nrdat) {
         IS->nrdat = nrdat;
         IS->rdat = (float *) realloc ((void *) IS->rdat,
                                       IS->nrdat * sizeof (float));
      }
      /* Make sure we have room for the GRID part of the output. */
      if (nd2x3 > IS->nd2x3) {
         IS->nd2x3 = nd2x3;
         IS->iain = (sInt4 *) realloc ((void *) IS->iain,
                                       IS->nd2x3 * sizeof (sInt4));
         IS->ib = (sInt4 *) realloc ((void *) IS->ib,
                                     IS->nd2x3 * sizeof (sInt4));
      }
      /* See note 3) If table50 == 3, unpacker library needs nd5 >= nd2x3. */
      if ((table50 == 3) || (table50 == 0)) {
         if (nd5 < nd2x3) {
            nd5 = nd2x3;
            if (nd5 > IS->ipackLen) {
               IS->ipackLen = nd5;
               IS->ipack = (sInt4 *) realloc ((void *) (IS->ipack),
                                              IS->ipackLen * sizeof (sInt4));
            }
            /* Don't need to do the following, but we do in case code
             * changes. */
            c_ipack = (char *) IS->ipack;
         }
      }
      IS->nd5 = nd5;
      /* Unpacker library requires ipack to be MSB. */
/*
#ifdef DEBUG
      if (1==1) {
         FILE *fp = fopen ("test.bin", "wb");
         fwrite (IS->ipack, sizeof (sInt4), IS->nd5, fp);
         fclose (fp);
      }
#endif
*/
#ifdef LITTLE_ENDIAN
      memswp (IS->ipack, sizeof (sInt4), IS->nd5);
#endif
   } else {
      gribLen = IS->ipack[3];
   }
   free (buff);

   /* Loop through the grib message looking for the subgNum grid.  subgNum
    * goes from 0 to n-1. */
   for (j = 0; j <= subgNum; j++) {
      if (j == 0) {
         inew = 1;
      } else {
         inew = 0;
      }

      /* Note we are getting data back either as a float or an int, but not
       * both, so we don't need to allocated room for both. */
      unpk_grib2 (&kfildo, (float *) (IS->iain), IS->iain, &(IS->nd2x3),
                  IS->idat, &(IS->nidat), IS->rdat, &(IS->nrdat), IS->is[0],
                  &(IS->ns[0]), IS->is[1], &(IS->ns[1]), IS->is[2],
                  &(IS->ns[2]), IS->is[3], &(IS->ns[3]), IS->is[4],
                  &(IS->ns[4]), IS->is[5], &(IS->ns[5]), IS->is[6],
                  &(IS->ns[6]), IS->is[7], &(IS->ns[7]), IS->ib, &ibitmap,
                  IS->ipack, &(IS->nd5), &xmissp, &xmisss, &inew, &iclean,
                  &l3264b, f_endMsg, jer, &ndjer, &kjer);
      /*
       * Check for error messages...
       *   If we get an error message, print it, and return.
       */
      for (i = 0; i < (uInt4) kjer; i++) {
         if (jer[ndjer + i] == 0) {
            /* no error. */
         } else if (jer[ndjer + i] == 1) {
            /* Warning. */
#ifdef DEBUG
            printf ("Warning: Unpack library warning code (%d %d)\n",
                    jer[i], jer[ndjer + i]);
#endif
         } else {
            /* BAD Error. */
            errSprintf ("ERROR: Unpack library error code (%ld %ld)\n",
                        jer[i], jer[ndjer + i]);
            return -3;
         }
      }
   }

   /* Parse the meta data out. */
   if (MetaParse (meta, IS->is[0], IS->ns[0], IS->is[1], IS->ns[1],
                  IS->is[2], IS->ns[2], IS->rdat, IS->nrdat, IS->idat,
                  IS->nidat, IS->is[3], IS->ns[3], IS->is[4], IS->ns[4],
                  IS->is[5], IS->ns[5], gribLen, xmissp, xmisss, simpVer)
       != 0) {
#ifdef DEBUG
      FILE *fp;
      if ((fp = fopen ("dump.is0", "wt")) != NULL) {
         for (i = 0; i < 8; i++) {
            fprintf (fp, "---Section %d---\n", (int) i);
            for (j = 1; j <= IS->ns[i]; j++) {
               fprintf (fp, "IS%d Item %d = %d\n", (int) i, (int) j, IS->is[i][j - 1]);
            }
         }
         fclose (fp);
      }
#endif
      preErrSprintf ("Inside ReadGrib2Record.. Problems in MetaParse\n");
      return -4;
   }

   if ((majEarth > 6000) && (majEarth < 7000)) {
      if ((minEarth > 6000) && (minEarth < 7000)) {
         meta->gds.f_sphere = 0;
         meta->gds.majEarth = majEarth;
         meta->gds.minEarth = minEarth;
      } else {
         meta->gds.f_sphere = 1;
         meta->gds.majEarth = majEarth;
         meta->gds.minEarth = majEarth;
      }
   }

   /* Figure out an equation to pass to ParseGrid to convert the units for
    * this grid. */
/*
   if (ComputeUnit (meta->pds2.prodType, meta->pds2.sect4.templat,
                    meta->pds2.sect4.cat, meta->pds2.sect4.subcat, f_unit,
                    &unitM, &unitB, unitName) == 0) {
*/
   if (ComputeUnit (meta->convert, meta->unitName, f_unit, &unitM, &unitB,
                    unitName) == 0) {
      unitLen = strlen (unitName);
      meta->unitName = (char *) realloc ((void *) (meta->unitName),
                                         1 + unitLen * sizeof (char));
      strncpy (meta->unitName, unitName, unitLen);
      meta->unitName[unitLen] = '\0';
   }

   /* compute the subgrid. */
   /*
   if ((lwlf->lat != -100) && (uprt->lat != -100)) {
      Nx = meta->gds.Nx;
      Ny = meta->gds.Ny;
      if (computeSubGrid (lwlf, &x1, &y1, uprt, &x2, &y2, &(meta->gds),
                          &newGds) != 0) {
         preErrSprintf ("ERROR: In compute subgrid.\n");
         return 1;
      }
      // I couldn't decide if I should "permanently" change the GDS or not.
      // when I wrote computeSubGrid.  If next line stays, really should
      // rewrite computeSubGrid.
      memcpy (&(meta->gds), &newGds, sizeof (gdsType));
      f_subGrid = 1;
   } else {
      Nx = meta->gds.Nx;
      Ny = meta->gds.Ny;
      x1 = 1;
      x2 = Nx;
      y1 = 1;
      y2 = Ny;
      f_subGrid = 0;
   }
   */
   Nx = meta->gds.Nx;
   Ny = meta->gds.Ny;
   x1 = 1;
   x2 = Nx;
   y1 = 1;
   y2 = Ny;
   f_subGrid = 0;

   /* Figure out if we need iain or ain, and set it to Grib_Data.  At the
    * same time handle any bitmaps, and compute some statistics. */
   if ((f_subGrid) && (meta->gds.scan != 64)) {
      errSprintf ("Can not do a subgrid of non scanmode 64 grid yet.\n");
      return -3;
   }

   if (strcmp (meta->element, "Wx") != 0) {
      ParseGrid (&(meta->gridAttrib), Grib_Data, grib_DataLen, Nx, Ny,
                 meta->gds.scan, IS->iain, ibitmap, IS->ib, unitM, unitB, 0,
                 NULL, f_subGrid, x1, y1, x2, y2);
   } else {
      /* Handle weather grid.  ParseGrid looks up the values... If they are
       * "<Invalid>" it sets it to missing (or creates one).  If the table
       * entry is used it sets f_valid to 2. */
      ParseGrid (&(meta->gridAttrib), Grib_Data, grib_DataLen, Nx, Ny,
                 meta->gds.scan, IS->iain, ibitmap, IS->ib, unitM, unitB, 1,
                 (sect2_WxType *) &(meta->pds2.sect2.wx), f_subGrid, x1, y1,
                 x2, y2);

      /* compact the table to only those which are actually used. */
      cnt = 0;
      for (i = 0; i < meta->pds2.sect2.wx.dataLen; i++) {
         if (meta->pds2.sect2.wx.ugly[i].f_valid == 2) {
            meta->pds2.sect2.wx.ugly[i].validIndex = cnt;
            cnt++;
         } else if (meta->pds2.sect2.wx.ugly[i].f_valid == 3) {
            meta->pds2.sect2.wx.ugly[i].f_valid = 0;
            meta->pds2.sect2.wx.ugly[i].validIndex = cnt;
            cnt++;
         } else {
            meta->pds2.sect2.wx.ugly[i].validIndex = -1;
         }
      }
   }

   /* Figure out some other non-section oriented meta data. */
/*   strftime (meta->refTime, 20, "%Y%m%d%H%M",
             gmtime (&(meta->pds2.refTime)));
*/
   Clock_Print (meta->refTime, 20, meta->pds2.refTime, "%Y%m%d%H%M", 0);
/*
   strftime (meta->validTime, 20, "%Y%m%d%H%M",
             gmtime (&(meta->pds2.sect4.validTime)));
*/
   Clock_Print (meta->validTime, 20, meta->pds2.sect4.validTime,
                "%Y%m%d%H%M", 0);

   meta->deltTime = (sInt4) (meta->pds2.sect4.validTime - meta->pds2.refTime);

   return 0;
}
Example #13
0
/*****************************************************************************
 * FindSectLen2to7() --
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *   Looks through a GRIB message and finds out the maximum size of each
 * section.  Simpler if there is only one grid in the message.
 *
 * ARGUMENTS
 * c_ipack = The current GRIB2 message. (Input)
 * gribLen = Length of c_ipack. (Input)
 *      ns = Array of section lengths. (Output)
 * sectNum = Which section to start with. (Input)
 *  curTot = on going total read from c_ipack. (Input)
 *   nd2x3 = Total number of grid points (Output)
 * table50 = Type of packing used. (See code table 5.0) (GS5_SIMPLE = 0,
 *           GS5_CMPLX = 2, GS5_CMPLXSEC = 3) (Output)
 *
 * FILES/DATABASES: None
 *
 * RETURNS: int (could use errSprintf())
 *  0 = OK
 * -1 = Ran of data in a section
 * -2 = Section not properly labeled.
 *
 * HISTORY
 *   3/2003 AAT: Created
 *
 * NOTES
 * 1) Assumes that the pack method of multiple grids are the same.
 *****************************************************************************
 */
static int FindSectLen2to7 (char *c_ipack, sInt4 gribLen, sInt4 ns[8],
                            char sectNum, sInt4 *curTot, sInt4 *nd2x3,
                            short int *table50)
{
   sInt4 sectLen;       /* The length of the current section. */
   sInt4 li_temp;       /* A temporary holder of sInt4s. */

   if ((sectNum == 2) || (sectNum == 3)) {
      /* Figure out the size of section 2 and 3. */
      if (*curTot + 5 > gribLen) {
         errSprintf ("ERROR: Ran out of data in Section 2 or 3\n");
         return -1;
      }
      /* Handle optional section 2. */
      if (c_ipack[*curTot + 4] == 2) {
         MEMCPY_BIG (&sectLen, c_ipack + *curTot, 4);
         *curTot = *curTot + sectLen;
         if (ns[2] < sectLen)
            ns[2] = sectLen;
         if (*curTot + 5 > gribLen) {
            errSprintf ("ERROR: Ran out of data in Section 3\n");
            return -1;
         }
      }
      /* Handle section 3. */
      if (c_ipack[*curTot + 4] != 3) {
         errSprintf ("ERROR: Section 3 labeled as %d\n",
                     c_ipack[*curTot + 4]);
         return -2;
      }
      MEMCPY_BIG (&sectLen, c_ipack + *curTot, 4);
      if (ns[3] < sectLen)
         ns[3] = sectLen;
      /* While we are here, grab the total number of grid points nd2x3. */
      MEMCPY_BIG (&li_temp, c_ipack + *curTot + 6, 4);
      if (*nd2x3 < li_temp)
         *nd2x3 = li_temp;
      *curTot = *curTot + sectLen;
   }
/*
#ifdef DEBUG
   printf ("Section len (2=%ld) (3=%ld)\n", ns[2], ns[3]);
#endif
*/

   /* Figure out the size of section 4. */
   if (*curTot + 5 > gribLen) {
      errSprintf ("ERROR: Ran out of data in Section 4\n");
      return -1;
   }
   if (c_ipack[*curTot + 4] != 4) {
      errSprintf ("ERROR: Section 4 labeled as %d\n", c_ipack[*curTot + 4]);
      return -2;
   }
   MEMCPY_BIG (&sectLen, c_ipack + *curTot, 4);
   if (ns[4] < sectLen)
      ns[4] = sectLen;
   *curTot = *curTot + sectLen;
/*
#ifdef DEBUG
   printf ("Section len (4=%ld < %ld)\n", sectLen, ns[4]);
#endif
*/

   /* Figure out the size of section 5. */
   if (*curTot + 5 > gribLen) {
      errSprintf ("ERROR: Ran out of data in Section 5\n");
      return -1;
   }
   if (c_ipack[*curTot + 4] != 5) {
      errSprintf ("ERROR: Section 5 labeled as %d\n", c_ipack[*curTot + 4]);
      return -2;
   }
   MEMCPY_BIG (&sectLen, c_ipack + *curTot, 4);
   /* While we are here, grab the packing method. */
   MEMCPY_BIG (table50, c_ipack + *curTot + 9, 2);
   if (ns[5] < sectLen)
      ns[5] = sectLen;
   *curTot = *curTot + sectLen;
/*
#ifdef DEBUG
   printf ("Section len (5=%ld < %ld)\n", sectLen, ns[5]);
#endif
*/

   /* Figure out the size of section 6. */
   if (*curTot + 5 > gribLen) {
      errSprintf ("ERROR: Ran out of data in Section 6\n");
      return -1;
   }
   if (c_ipack[*curTot + 4] != 6) {
      errSprintf ("ERROR: Section 6 labeled as %d\n", c_ipack[*curTot + 4]);
      return -2;
   }
   MEMCPY_BIG (&sectLen, c_ipack + *curTot, 4);
   if (ns[6] < sectLen)
      ns[6] = sectLen;
   *curTot = *curTot + sectLen;
/*
#ifdef DEBUG
   printf ("Section len (6=%ld < %ld)\n", sectLen, ns[6]);
#endif
*/

   /* Figure out the size of section 7. */
   if (*curTot + 5 > gribLen) {
      errSprintf ("ERROR: Ran out of data in Section 7\n");
      return -1;
   }
   if (c_ipack[*curTot + 4] != 7) {
      errSprintf ("ERROR: Section 7 labeled as %d\n", c_ipack[*curTot + 4]);
      return -2;
   }
   MEMCPY_BIG (&sectLen, c_ipack + *curTot, 4);
   if (ns[7] < sectLen)
      ns[7] = sectLen;
   *curTot = *curTot + sectLen;
/*
#ifdef DEBUG
   printf ("Section len (7=%ld < %ld)\n", sectLen, ns[7]);
#endif
*/
   return 0;
}
Example #14
0
/*****************************************************************************
 * ReadSect0() -- Review 12/2002
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *   Looks for the next GRIB message, by looking for the keyword "GRIB".  It
 * expects the message in "expect" bytes from the start, but could find the
 * message in "expect2" bytes or 0 bytes from the start.  Returns -1 if it
 * can't find "GRIB", 1 if "GRIB" is not 0, "expect", or "expect2" bytes from
 * the start.
 *   It stores the bytes it reads (a max of "expect") upto but not including
 * the 'G' in "GRIB" in wmo.
 *
 *   After it finds section 0, it then parses the 16 bytes that make up
 * section 0 so that it can return the length of the entire GRIB message.
 *
 *   When done, it sets fp to point to the end of Sect0.
 *
 *   The reason for this procedure is so that we can read in the size of the
 * grib message, and thus allocate enough memory to read the message in before
 * making it Big endian, and passing it to the library for unpacking.
 *
 * ARGUMENTS
 *       fp = A pointer to an opened file in which to read.
 *            When done, this points to the start of section 1. (Input/Output)
 *     buff = The data between messages. (Input/Output)
 *  buffLen = The length of buff (Output)
 *    limit = How many bytes to read before giving up and stating it is not
 *            a proper message.  (-1 means no limit). (Input)
 *    sect0 = The read in Section 0 (as seen on disk). (Output)
 *  gribLen = Length of this GRIB message. (Output)
 *  version = 1 if GRIB1 message, 2 if GRIB2 message, -1 if TDLP message.
 *            (Output)
 *   expect = The expected number of bytes to find "GRIB" in. (Input)
 *  expect2 = The second possible number of bytes to find "GRIB" in. (Input)
 *      wmo = Assumed allocated to be at least size "expect".
 *            Holds the bytes before the first "GRIB" message.
 *            expect should be > expect2, but is up to caller (Output)
 *   wmoLen = Length of wmo (total number of bytes read - SECT0LEN_WORD * 4).
 *            (Output)
 *
 * FILES/DATABASES:
 *   An already opened "GRIB2" File
 *
 * RETURNS: int (could use errSprintf())
 *  1 = Length of wmo was != 0 and was != expect
 *  0 = OK
 * -1 = Couldn't find "GRIB" part of message.
 * -2 = Ran out of file while reading this section.
 * -3 = Grib version was not 1 or 2.
 * -4 = Most significant sInt4 of GRIB length was not 0
 * -5 = Grib message length was <= 16 (can't be smaller than just sect 0)
 *
 * HISTORY
 *   9/2002 Arthur Taylor (MDL/RSIS): Created.
 *  11/2002 AAT: Combined with ReadWMOHeader
 *  12/2002 (TK,AC,TB,&MS): Code Review.
 *   1/2003 AAT: Bug found. wmo access out of bounds of expect when setting
 *          the /0 element, if wmoLen > expect.
 *   4/2003 AAT: Added ability to handle GRIB version 1.
 *   5/2003 AAT: Added limit option.
 *   8/2003 AAT: Removed dependence on offset, and fileLen.
 *  10/2004 AAT: Modified to allow for TDLP files
 *
 * NOTES
 * 1a) 1196575042L == ASCII representation of "GRIB" (GRIB in MSB)
 * 1b) 1112101447L == ASCII representation of "BIRG" (GRIB in LSB)
 * 1c) 1413762128L == ASCII representation of "TDLP" (TDLP in MSB)
 * 1d) 1347175508L == ASCII representation of "PLDT" (TDLP in LSB)
 * 2) Takes advantage of the wordType to check that the edition is correct.
 * 3) May want to return prodType.
 * 4) WMO_HEADER_ORIG_LEN was added for backward compatibility... should be
 *    removed when we no longer use old format. (say in a year from 11/2002)
 *
 *****************************************************************************
 */
int ReadSECT0 (DataSource &fp, char **buff, uInt4 *buffLen, sInt4 limit,
               sInt4 sect0[SECT0LEN_WORD], uInt4 *gribLen, int *version)
{
   typedef union {
      sInt4 li;
      unsigned char buffer[4];
   } wordType;

   uChar gribMatch = 0; /* Counts how many letters in GRIB we've matched. */
   uChar tdlpMatch = 0; /* Counts how many letters in TDLP we've matched. */
   wordType word;       /* Used to check that the edition is correct. */
   uInt4 curLen;        /* Where we currently are in buff. */
   uInt4 i;             /* Used to loop over the first few char's */
   uInt4 stillNeed;     /* Number of bytes still needed to get 1st 8 bytes of 
                         * message into memory. */

   /* Get first 8 bytes.  If GRIB we don't care.  If TDLP, this is the length 
    * of record.  Read at least 1 record (length + 2 * 8) + 8 (next record
    * length) + 8 bytes before giving up. */
   curLen = 8;
   if (*buffLen < curLen) {
      *buffLen = curLen;
      *buff = (char *) realloc ((void *) *buff, *buffLen * sizeof (char));
   }
   if (fp.DataSourceFread(*buff, sizeof (char), curLen) != curLen) {
      errSprintf ("ERROR: Couldn't find 'GRIB' or 'TDLP'\n");
      return -1;
   }
/*
   Can't do the following because we don't know if the file is a GRIB file or
   not, or if it was a FORTRAN file.
   if (limit > 0) {
      MEMCPY_BIG (&recLen, *buff, 4);
      limit = (limit > recLen + 32) ? limit : recLen + 32;
   }
*/
   while ((tdlpMatch != 4) && (gribMatch != 4)) {
      for (i = curLen - 8; i + 3 < curLen; i++) {
         if ((*buff)[i] == 'G') {
            if (((*buff)[i + 1] == 'R') && ((*buff)[i + 2] == 'I') &&
                ((*buff)[i + 3] == 'B')) {
               gribMatch = 4;
               break;
            }
         } else if ((*buff)[i] == 'T') {
            if (((*buff)[i + 1] == 'D') && ((*buff)[i + 2] == 'L') &&
                ((*buff)[i + 3] == 'P')) {
               tdlpMatch = 4;
               break;
            }
         }
      }
      stillNeed = i - (curLen - 8);
      /* Read enough of message to have the first 8 bytes (including ID). */
      if (stillNeed != 0) {
         curLen += stillNeed;
         if ((limit >= 0) && (curLen > (size_t) limit)) {
            errSprintf ("ERROR: Couldn't find type in %ld bytes\n", limit);
            return -1;
         }
         if (*buffLen < curLen) {
            *buffLen = curLen;
            *buff = (char *) realloc ((void *) *buff,
                                      *buffLen * sizeof (char));
         }
         if (fp.DataSourceFread((*buff) + (curLen - stillNeed), sizeof (char), stillNeed) != stillNeed) {
            errSprintf ("ERROR: Ran out of file reading SECT0\n");
            return -1;
         }
      }
   }

   /* curLen and (*buff) hold 8 bytes of section 0. */
   curLen -= 8;
   memcpy (&(sect0[0]), (*buff) + curLen, 4);
#ifdef DEBUG
#ifdef LITTLE_ENDIAN
   myAssert ((sect0[0] == 1112101447L) || (sect0[0] == 1347175508L));
#else
   myAssert ((sect0[0] == 1196575042L) || (sect0[0] == 1413762128L));
#endif
#endif
   memcpy (&(sect0[1]), *buff + curLen + 4, 4);
   /* Make sure we don't pass back part of "GRIB" in the buffer. */
   (*buff)[curLen] = '\0';
   *buffLen = curLen;

   word.li = sect0[1];
   if (tdlpMatch == 4) {
      if (word.buffer[3] != 0) {
         errSprintf ("ERROR: unexpected version of TDLP in SECT0\n");
         return -2;
      }
      *version = -1;
      /* Find out the GRIB Message Length */
      *gribLen = GRIB_UNSIGN_INT3 (word.buffer[0], word.buffer[1],
                                   word.buffer[2]);
      /* Min message size: GRIB1=52, TDLP=59, GRIB2=86. */
      if (*gribLen < 59) {
         errSprintf ("TDLP length %ld was < 59?\n", *gribLen);
         return -5;
      }
   } else if (word.buffer[3] == 1) {
      *version = 1;
      /* Find out the GRIB Message Length */
      *gribLen = GRIB_UNSIGN_INT3 (word.buffer[0], word.buffer[1],
                                   word.buffer[2]);
      /* Min message size: GRIB1=52, TDLP=59, GRIB2=86. */
      if (*gribLen < 52) {
         errSprintf ("GRIB1 length %ld was < 52?\n", *gribLen);
         return -5;
      }
   } else if (word.buffer[3] == 2) {
      *version = 2;
      /* Make sure we still have enough file for the rest of section 0. */
      if (fp.DataSourceFread(sect0 + 2, sizeof (sInt4), 2) != 2) {
         errSprintf ("ERROR: Ran out of file reading SECT0\n");
         return -2;
      }
      if (sect0[2] != 0) {
         errSprintf ("Most significant sInt4 of GRIB length was not 0?\n");
         errSprintf ("This is either an error, or we have a single GRIB "
                     "message which is larger than 2^31 = 2,147,283,648 "
                     "bytes.\n");
         return -4;
      }
#ifdef LITTLE_ENDIAN
      revmemcpy (gribLen, &(sect0[3]), sizeof (sInt4));
#else
      *gribLen = sect0[3];
#endif
   } else {
      errSprintf ("ERROR: Not TDLPack, and Grib edition is not 1 or 2\n");
      return -3;
   }
   return 0;
}
Example #15
0
/*****************************************************************************
 * GRIB2Split() --
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *   Splits a file into its component GRIB messages (doesn't break up
 * subgrids).
 *
 * ARGUMENTS
 * filename = File to split. (Input)
 *   msgNum = Which message to look for (0 all, value otherwise). (Input)
 *   curMsg = Number of messages we've already looked at.
 *            In the procedured is the current message we are on. (Input)
 *
 * FILES/DATABASES:
 *    Opens a GRIB2 file for reading given its filename.
 *
 * RETURNS: int
 * +# = number of GRIB2 messages in the file.
 * -1 = Problems opening file for read.
 *
 * HISTORY
 *   5/2010 Arthur Taylor (MDL): Created.
 *
 * NOTES
 *****************************************************************************
 */
int GRIB2Split (char *filename, int msgNum, int curMsg)
{
   int grib_limit;      /* How many bytes to look for before the first "GRIB"
                         * in the file.  If not found, is not a GRIB file. */
   FILE *fp;            /* The opened GRIB2 file. */
   sInt4 offset = 0;    /* Where we are in the file. */
   char *ptr;           /* used to find the file extension. */
   char *buff;          /* Holds the info between records. */
   uInt4 buffLen;       /* Length of info between records. */
   int c;               /* Determine if end of the file without fileLen. */
   sInt4 sect0[SECT0LEN_WORD]; /* Holds the current Section 0. */
   uInt4 gribLen;       /* Length of the current GRIB message. */
   int version;         /* Which version of GRIB is in this message. */
   char *msg;           /* Used to pop messages off the error Stack. */
   sInt4 fileLen;       /* Length of the GRIB2 file. */
   char *outName = NULL; /* Name of the output file. */
   FILE *op;            /* The opened output file. */
   int i;               /* loop counter while writing bytes to output file. */

   grib_limit = GRIB_LIMIT;
   if (filename != NULL) {
      if ((fp = fopen (filename, "rb")) == NULL) {
         errSprintf ("ERROR: Problems opening %s for read.", filename);
         return -1;
      }
      ptr = strrchr (filename, '.');
      if (ptr != NULL) {
         if (strcmp (ptr, ".tar") == 0) {
            grib_limit = 5000;
         }
      }
      outName = (char *) malloc (strlen (filename) + 1 + 11);
   } else {
      fp = stdin;
      outName = (char *) malloc (strlen ("split.grb") + 1 + 11);
   }

   buff = NULL;
   buffLen = 0;
   while ((c = fgetc (fp)) != EOF) {
      ungetc (c, fp);
      /* curMsg++ done first so any error messages range from 1..n, instead
       * of 0.. n-1. Note curMsg should end up as n not (n-1) */
      curMsg++;
      /* Allow  2nd, 3rd, etc messages to have no limit to finding "GRIB". */
      if (curMsg > 1) {
         grib_limit = -1;
      }
      /* Read in the wmo header and sect0. */
      if (ReadSECT0 (fp, &buff, &buffLen, grib_limit, sect0, &gribLen,
                     &version) < 0) {
         if (curMsg == 1) {
            /* Handle case where we couldn't find 'GRIB' in the message. */
            preErrSprintf ("Inside GRIB2Split, Message # %d\n", curMsg);

            free (buff);
            free (outName);
            fclose (fp);
            return -2;
         } else {
            /* Handle case where there are trailing bytes. */
            msg = errSprintf (NULL);
            printf ("Warning: Inside GRIB2Split, Message # %d\n",
                    curMsg);
            printf ("%s", msg);
            free (msg);
            /* find out how big the file is. */
            fseek (fp, 0L, SEEK_END);
            fileLen = ftell (fp);
            /* fseek (fp, 0L, SEEK_SET); */
            printf ("There were %ld trailing bytes in the file.\n",
                    fileLen - offset);
            curMsg --;

            free (buff);
            free (outName);
            fclose (fp);
            return curMsg;
         }
      }

      if (version == -1) {
         /* TDLPack uses 4 bytes for FORTRAN record size, then another 8
          * bytes for the size of the record (so FORTRAN can see it), then
          * the data rounded up to an 8 byte boundary, then a trailing 4
          * bytes for a final FORTRAN record size.  However it only stores
          * in_ the gribLen the non-rounded amount, so we need to take care
          * of the rounding, and the trailing 4 bytes here. */
         gribLen = ((sInt4) ceil (gribLen / 8.0)) * 8 + 4;
      }

      /* Write to file from buffLen to buffLen + gribLen bytes. */
      if ((msgNum == 0) || (curMsg == msgNum)) {
         if (filename != NULL) {
            sprintf (outName, "%s.%d", filename, curMsg);
         } else {
            sprintf (outName, "split.grb.%d", curMsg);
         }
         if ((op = fopen (outName, "wb")) == NULL) {
            errSprintf ("ERROR: Problems opening %s for write.", outName);

            free (buff);
            free (outName);
            fclose (fp);
            return -1;
         }
         fseek (fp, offset + buffLen, SEEK_SET);
         for (i = 0; i < gribLen; i++) {
            if ((c = getc(fp)) == EOF) {
               errSprintf ("ERROR: Reached end of file too soon?");

               free (buff);
               free (outName);
               fclose (fp);
               return -1;
            }
            putc (c, op);
         }
         fclose (op);
      }

      /* Continue on to the next GRIB2 message. */
      offset += buffLen + gribLen;
      fseek (fp, offset, SEEK_SET);
   }

   free (buff);
   free (outName);
   fclose (fp);
   return curMsg;
}