/***************************************************************************** * memBitRead() -- * * Arthur Taylor / MDL * * PURPOSE * To read bits from an uChar buffer array of memory. Assumes BufLoc is * valid before first call. Typically this means do a "bufLoc = 8;" before * the first call. * * ARGUMENTS * Dst = Where to put the results. (Output) * dstLen = Length in bytes of Dst. (Input) * Src = The data to read the bits from. (Input) * numBits = How many bits to read. (Input) * BufLoc = Which bit to start reading from in Src. * Starts at 8 goes to 1. (Input/Output) * numUsed = How many bytes from Src were used while reading (Output) * * FILES/DATABASES: None * * RETURNS: * Returns 1 on error, 0 if ok. * * HISTORY * 4/2003 Arthur Taylor (MDL/RSIS): Created * 5/2004 AAT: Bug in call to MEMCPY_BIG when numBytes != dstLen. * On big endian machines we need to right justify the number. * * NOTES * 1) Assumes binary bit stream is "big endian". Resulting in no byte * boundaries i.e. 00100110101101 => 001001 | 10101101 ***************************************************************************** */ char memBitRead (void *Dst, size_t dstLen, void *Src, size_t numBits, uChar * bufLoc, size_t * numUsed) { uChar *src = (uChar *) Src; /* Allows us to treat Src as an array of * char. */ uChar *dst = (uChar *) Dst; /* Allows us to treat Dst as an array of * char. */ size_t numBytes; /* How many bytes are needed in dst. */ uChar dstLoc; /* Where we are writing to in dst. */ uChar *ptr; /* Current byte we are writing to in dst. */ static uChar BitMask[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; if (numBits == 0) { memset (Dst, 0, dstLen); (*numUsed) = 0; return 0; } numBytes = ((numBits - 1) / 8) + 1; if (dstLen < numBytes) { return 1; } memset (Dst, 0, dstLen); dstLoc = ((numBits - 1) % 8) + 1; if ((*bufLoc == 8) && (dstLoc == 8)) { #ifdef LITTLE_ENDIAN MEMCPY_BIG (Dst, Src, numBytes); #else /* If numBytes != dstLen, then we need to right justify the ans */ MEMCPY_BIG (dst + (dstLen - numBytes), Src, numBytes); #endif (*numUsed) = numBytes; return 0; } #ifdef LITTLE_ENDIAN ptr = dst + (numBytes - 1); #else ptr = dst + (dstLen - numBytes); #endif *numUsed = 0; /* Deal with most significant byte in dst. */ if (*bufLoc >= dstLoc) { #ifdef LITTLE_ENDIAN (*ptr--) |= ((*src & BitMask[*bufLoc]) >> (*bufLoc - dstLoc)); #else (*ptr++) |= ((*src & BitMask[*bufLoc]) >> (*bufLoc - dstLoc)); #endif (*bufLoc) -= dstLoc; } else {
/***************************************************************************** * memBitRead() -- Arthur Taylor / MDL * * PURPOSE * To read bits from an uChar buffer array of memory. Assumes BufLoc is * valid before first call. Typically this means do a "bufLoc = 8;" before * the first call. * * ARGUMENTS * Dst = Where to put the results. (Output) * dstLen = Length in bytes of Dst. (Input) * Src = The data to read the bits from. (Input) * numBits = How many bits to read. (Input) * BufLoc = In Src, which bit to start reading from. * Starts at 8 goes to 1. (Input/Output) * numUsed = How many bytes from Src were used while reading (Output) * * RETURNS: int * 1 on error, 0 if ok. * * HISTORY * 4/2003 Arthur Taylor (MDL/RSIS): Created * 5/2004 AAT: Bug in call to MEMCPY_BIG when numBytes != dstLen. * On big endian machines we need to right justify the number. * 3/2007 AAT (MDL): Commented * * NOTES * 1) Assumes binary bit stream is "big endian". Resulting in no byte * boundaries ie 00100110101101 => 001001 | 10101101 ****************************************************************************/ int memBitRead(void *Dst, size_t dstLen, const void *Src, size_t numBits, uChar *bufLoc, size_t *numUsed) { uChar *src = (uChar *)Src; /* Allows us to treat Src as array of char. */ uChar *dst = (uChar *)Dst; /* Allows us to treat Dst as array of char. */ size_t numBytes; /* How many bytes are needed in dst. */ uChar dstLoc; /* Where we are writing to in dst. */ uChar *ptr; /* Current byte we are writing to in dst. */ /* uses: static const uChar BitMask[] */ if (numBits == 0) { memset(Dst, 0, dstLen); (*numUsed) = 0; return 0; } /* Since numBits is always used with -1, may as well do --numBits here. */ numBytes = ((--numBits) / 8) + 1; /* Check if dst has enough room. */ if (dstLen < numBytes) { myWarn_Err1Arg("Dst doesn't have enough space\n"); return 1; } memset(Dst, 0, dstLen); dstLoc = (uChar)((numBits % 8) + 1); if ((*bufLoc == 8) && (dstLoc == 8)) { #ifndef WORDS_BIGENDIAN MEMCPY_BIG(Dst, Src, numBytes); #else /* If numBytes != dstLen, then we need to right justify the ans */ MEMCPY_BIG(dst + (dstLen - numBytes), Src, numBytes); #endif (*numUsed) = numBytes; return 0; } #ifndef WORDS_BIGENDIAN ptr = dst + (numBytes - 1); #else ptr = dst + (dstLen - numBytes); #endif *numUsed = 0; /* Deal with most significant byte in dst. */ if (*bufLoc >= dstLoc) { #ifndef WORDS_BIGENDIAN (*ptr--) |= ((*src & BitMask[*bufLoc]) >> (*bufLoc - dstLoc)); #else (*ptr++) |= ((*src & BitMask[*bufLoc]) >> (*bufLoc - dstLoc)); #endif (*bufLoc) -= dstLoc; } else {
/***************************************************************************** * 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; }
/***************************************************************************** * InventoryParseTime() -- Review 12/2002 * * Arthur Taylor / MDL * * PURPOSE * To parse the time data from a grib2 char array to a time_t in UTC * seconds from the epoch. This is very similar to metaparse.c:ParseTime * except using char * instead of sInt4 * * ARGUMENTS * is = The char array to read the time info from. (Input) * AnsTime = The time_t value to fill with the resulting time. (Output) * * FILES/DATABASES: None * * RETURNS: void * * HISTORY * 11/2002 Arthur Taylor (MDL/RSIS): Created. * 12/2002 (TK,AC,TB,&MS): Code Review. * * NOTES * 1) Couldn't use the default time_zone variable (concern over portability * issues), so we print the hours, and compare them to the hours we had * intended. Then subtract the difference from the AnsTime. * 2) Similar to metaparse.c:ParseTime except using char * instead of sInt4 ***************************************************************************** */ static int InventoryParseTime (char *is, double *AnsTime) { /* struct tm time; *//* A temporary variable to put the time info into. */ /* char buffer[10]; *//* Used when printing the AnsTime's Hr. */ /* int timeZone; *//* The adjustment in Hr needed to get the right UTC * time. */ short int si_temp; /* Temporarily stores the year as a short int to fix * possible endian problems. */ /* memset (&time, 0, sizeof (struct tm));*/ MEMCPY_BIG (&si_temp, is + 0, sizeof (short int)); if ((si_temp < 1900) || (si_temp > 2100)) { return -1; } if ((is[2] > 12) || (is[3] == 0) || (is[3] > 31) || (is[4] > 24) || (is[5] > 60) || (is[6] > 61)) { return -1; } Clock_ScanDate (AnsTime, si_temp, is[2], is[3]); *AnsTime += is[4] * 3600. + is[5] * 60. + is[6]; /* time.tm_year = si_temp - 1900; time.tm_mon = is[2] - 1; time.tm_mday = is[3]; time.tm_hour = is[4]; time.tm_min = is[5]; time.tm_sec = is[6]; *AnsTime = mktime (&time) - (Clock_GetTimeZone () * 3600); */ /* Cheap method of getting global time_zone variable. */ /* strftime (buffer, 10, "%H", gmtime (AnsTime)); timeZone = atoi (buffer) - is[4]; if (timeZone < 0) { timeZone += 24; } *AnsTime = *AnsTime - (timeZone * 3600); */ 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; }
/***************************************************************************** * 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; }