/***************************************************************************** * 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; }
/***************************************************************************** * 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 (§Len, 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; }
/* 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; }
/***************************************************************************** * 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; }
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); }
/***************************************************************************** * 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 (§Num, 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; }
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 ); }
/***************************************************************************** * 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; }
/***************************************************************************** * 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, §Num, &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 (¢er, 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 (§Num, 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; }
/***************************************************************************** * 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, §Num, &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, §Num, &secLen) != 0) { errSprintf ("ERROR: Problems Jumping past section 3\n"); return -6; } } } /* Read section 4 into buffer. */ sectNum = 4; if (GRIB2SectToBuffer (fp, gribLen, §Num, &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, §Num, &secLen) != 0) { errSprintf ("ERROR: Problems Jumping past section 5\n"); return -9; } /* Jump past section 6. */ sectNum = 6; if (GRIB2SectJump (fp, gribLen, §Num, &secLen) != 0) { errSprintf ("ERROR: Problems Jumping past section 6\n"); return -10; } /* Jump past section 7. */ sectNum = 7; if (GRIB2SectJump (fp, gribLen, §Num, &secLen) != 0) { errSprintf ("ERROR: Problems Jumping past section 7\n"); return -11; } return 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, §Num, &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; }
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; }
/***************************************************************************** * 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 (§Len, 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 (§Len, 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 (§Len, 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 (§Len, 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 (§Len, 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 (§Len, 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; }
/***************************************************************************** * 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; }
/***************************************************************************** * 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; }