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