1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 
5 #include "iterator_grib.h"
6 
7 #include "cdi.h"
8 #include "cdi_int.h"
9 #include "dmemory.h"
10 #include "error.h"
11 #include "gribapi.h"
12 #include "gribapi_utilities.h"
13 #include "stream_grb.h"
14 #include "zaxis.h"
15 
16 #include <assert.h>
17 #include <limits.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 
22 #ifdef HAVE_LIBGRIB_API
23 
24 struct CdiGribIterator {
25   CdiIterator super;
26 
27   CdiInputFile *file;
28   off_t fileOffset;
29   unsigned char *gribBuffer;
30   size_t bufferSize, curRecordSize;
31   grib_handle *gribHandle;
32 };
33 
cdiGribIterator_getSuper(CdiGribIterator * me)34 CdiIterator *cdiGribIterator_getSuper(CdiGribIterator *me)
35 {
36   return &me->super;
37 }
38 
39 //Since the error handling in constructors is usually very closely related to the workings of a destructor,
40 //this function combines both functions in one, using a centralized exit.
41 //The mode of operation depends on whether me is a NULL pointer on entry:
42 //If it is NULL, a new object is allocated and constructed, which is returned if construction is successful.
43 //If a non-NULL pointer is passed in, the object is destructed and NULL is returned. In this case, the other arguments are ignored.
cdiGribIterator_condestruct(CdiGribIterator * me,const char * path,int filetype)44 static CdiGribIterator *cdiGribIterator_condestruct(CdiGribIterator *me, const char *path, int filetype)
45 {
46 #define super() (&me->super)
47   if(me) goto destruct;
48   me = (CdiGribIterator *) Malloc(sizeof(*me));
49   baseIterConstruct(super(), filetype);
50 
51   me->file = cdiInputFile_make(path);
52   if(!me->file) goto destructSuper;
53   me->fileOffset = 0;
54   me->gribHandle = NULL;
55   me->gribBuffer = NULL;
56   me->bufferSize = me->curRecordSize = 0;
57   me->super.gridId = CDI_UNDEFID;
58 
59   goto success;
60 
61 // ^        constructor code        ^
62 // |                                |
63 // v destructor/error-cleanup code  v
64 
65 destruct:
66   if(me->super.gridId != CDI_UNDEFID) gridDestroy(me->super.gridId);
67   if(me->gribHandle) grib_handle_delete((struct grib_handle *)me->gribHandle);
68   Free(me->gribBuffer);
69   cdiRefObject_release(&me->file->super);
70 destructSuper:
71   baseIterDestruct(super());
72   Free(me);
73   me = NULL;
74 
75 success:
76   return me;
77 #undef super
78 }
79 
cdiGribIterator_new(const char * path,int filetype)80 CdiIterator *cdiGribIterator_new(const char *path, int filetype)
81 {
82   return &cdiGribIterator_condestruct(NULL, path, filetype)->super;
83 }
84 
cdiGribIterator_makeClone(CdiIterator * super)85 CdiGribIterator *cdiGribIterator_makeClone(CdiIterator *super)
86 {
87   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
88 
89   //Allocate memory and copy data. (operations that may fail)
90   CdiGribIterator *result = (struct CdiGribIterator *) Malloc(sizeof(*result));
91   if(!result) goto fail;
92 
93   result->file = me->file;
94   result->fileOffset = me->fileOffset;
95   result->gribBuffer = NULL;
96   result->bufferSize = me->bufferSize;
97   result->curRecordSize = me->curRecordSize;
98   result->gribHandle = NULL;
99 
100   if(me->gribBuffer)
101     {
102       result->gribBuffer = (unsigned char *) Malloc(me->bufferSize);
103       if(!result->gribBuffer) goto freeResult;
104       memcpy(result->gribBuffer, me->gribBuffer, me->curRecordSize);
105     }
106   if(me->gribHandle)
107     {
108       result->gribHandle = grib_handle_new_from_message(NULL, result->gribBuffer, result->curRecordSize);
109       if(!result->gribHandle) goto freeBuffer;
110     }
111   if(super->gridId != CDI_UNDEFID)
112     {
113       result->super.gridId = gridDuplicate(super->gridId);
114       if(result->super.gridId == CDI_UNDEFID) goto deleteGribHandle;
115     }
116 
117   //Finish construction. (operations that cannot fail)
118   baseIterConstruct(&result->super, super->filetype);
119   result->super.datatype = super->datatype;
120   result->super.timesteptype = super->timesteptype;
121   result->super.param = super->param;
122   cdiRefObject_retain(&result->file->super);
123 
124   return result;
125 
126   //Error handling.
127 deleteGribHandle:
128   if(result->gribHandle) grib_handle_delete(result->gribHandle);
129 freeBuffer:
130   Free(result->gribBuffer);
131 freeResult:
132   Free(result);
133 fail:
134   return NULL;
135 }
136 
cdiGribIterator_serialize(CdiIterator * super)137 char *cdiGribIterator_serialize(CdiIterator *super)
138 {
139   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
140 
141   const char *path = cdiInputFile_getPath(me->file);
142   char *escapedPath = cdiEscapeSpaces(path);
143   char *result = (char *) Malloc(strlen(escapedPath) + 3 * sizeof(int) * CHAR_BIT/8);
144   sprintf(result, "%s %zu", escapedPath, (size_t)me->fileOffset);
145   Free(escapedPath);
146   return result;
147 }
148 
149 
cdiGribIterator_deserialize(const char * description)150 CdiGribIterator *cdiGribIterator_deserialize(const char *description)
151 {
152   char *path;
153   CdiGribIterator *me = (CdiGribIterator *) Malloc(sizeof(*me));
154   if(!me) goto fail;
155 
156   description = baseIter_constructFromString(&me->super, description);
157 
158   while(*description == ' ') description++;
159   path = cdiUnescapeSpaces(description, &description);
160   if(!path) goto destructSuper;
161 
162   me->file = cdiInputFile_make(path);
163   Free(path);
164   if(!me->file) goto destructSuper;
165 
166   {
167     const char *savedStart = description;
168     char *description_ = (char *)description;
169     long long decodedOffset = strtoll(description, &description_, 0);
170     description = description_;
171     me->fileOffset = (off_t)decodedOffset;
172     if(savedStart == description) goto closeFile;
173     if((unsigned long long)decodedOffset > (unsigned long long)me->fileOffset) goto closeFile;
174   }
175 
176   me->gribBuffer = NULL;
177   me->bufferSize = me->curRecordSize = 0;
178   me->gribHandle = NULL;
179   me->super.gridId = CDI_UNDEFID;
180   if(me->super.isAdvanced && cdiGribIterator_nextField(&me->super)) goto closeFile;
181 
182   return me;
183 
184 
185 closeFile:
186   cdiRefObject_release(&me->file->super);
187 destructSuper:
188   baseIterDestruct(&me->super);
189   Free(me);
190 fail:
191   return NULL;
192 }
193 
cdiGribIterator_ensureBuffer(CdiGribIterator * me,size_t requiredSize)194 static void cdiGribIterator_ensureBuffer(CdiGribIterator *me, size_t requiredSize)
195 {
196   if(me->bufferSize < requiredSize)
197     {
198       me->bufferSize *= 2;
199       if(me->bufferSize < requiredSize) me->bufferSize = requiredSize;
200       me->gribBuffer = (unsigned char *) Realloc(me->gribBuffer, me->bufferSize);
201     }
202 }
203 
isGrib1DualLevel(int levelType)204 static bool isGrib1DualLevel(int levelType)
205 {
206   switch(levelType)
207     {
208       case 101: case 104: case 106: case 108: case 110: case 112:
209       case 114: case 116: case 120: case 121: case 128: case 141:   //This is the complete list after grib_api-1.12.3/definitions/grib1/sections.1.def:106-117:, the code in cdi/src/stream_gribapi.c:grib1GetLevel() seems to be incomplete.
210         return true;
211       default:
212         return false;
213     }
214 }
215 
positionOfGribMarker(const unsigned char * data,size_t size)216 static const unsigned char *positionOfGribMarker(const unsigned char *data, size_t size)
217 {
218   for(const unsigned char *currentPosition = data, *end = data + size; currentPosition < end; currentPosition++)
219     {
220       currentPosition = (unsigned char *)memchr(currentPosition, 'G', size - (size_t)(currentPosition - data) - 3);      //-3 to ensure that we don't overrun the buffer during the strncmp() call.
221       if(!currentPosition) return NULL;
222       if(!strncmp((const char*)currentPosition, "GRIB", 4)) return currentPosition;
223     }
224   return NULL;
225 }
226 
227 //This clobbers the contents of the gribBuffer!
228 //Returns the file offset of the next 'GRIB' marker.
scanToGribMarker(CdiGribIterator * me)229 static ssize_t scanToGribMarker(CdiGribIterator *me)
230 {
231   cdiGribIterator_ensureBuffer(me, 8*1024);
232   const size_t kMaxScanSize = 16*1024*1024;
233   for(size_t scannedBytes = 0, scanSize; scannedBytes < kMaxScanSize; scannedBytes += scanSize)
234     {
235       //Load a chunk of data into our buffer.
236       scanSize = me->bufferSize;
237       if(scannedBytes + scanSize > kMaxScanSize) scanSize = kMaxScanSize - scannedBytes;
238       assert(scanSize <= me->bufferSize);
239       int status = cdiInputFile_read(me->file, me->fileOffset + (off_t)scannedBytes, scanSize, &scanSize, me->gribBuffer);
240       if(status != CDI_NOERR && status != CDI_EEOF) return -1;
241 
242       const unsigned char *startPosition = positionOfGribMarker(me->gribBuffer, scanSize);
243       if(startPosition)
244         {
245           return (ssize_t)(me->fileOffset + (off_t)scannedBytes + (off_t)(startPosition - me->gribBuffer));
246         }
247 
248       //Get the offset for the next iteration if there is a next iteration.
249       scanSize -= 3;        //so that we won't miss a 'GRIB' sequence that happens to be cut off
250       scanSize &= ~(size_t)0xf; //make 16 bytes aligned
251       if((ssize_t)scanSize <= 0) return -1; //ensure that we make progress
252     }
253   return -1;
254 }
255 
decode24(void * beData)256 static unsigned decode24(void *beData)
257 {
258   unsigned char *bytes = (unsigned char *)beData;
259   return ((unsigned)bytes[0] << 16) + ((unsigned)bytes[1] << 8) + (unsigned)bytes[2];
260 }
261 
decode64(void * beData)262 static uint64_t decode64(void *beData)
263 {
264   unsigned char *bytes = (unsigned char *)beData;
265   uint64_t result = 0;
266   for(size_t i = 0; i < 8; i++) result = (result << 8) + bytes[i];
267   return result;
268 }
269 
270 //Determine the size of the GRIB record that begins at the given file offset.
getRecordSize(CdiGribIterator * me,off_t gribFileOffset,size_t * outRecordSize)271 static int getRecordSize(CdiGribIterator *me, off_t gribFileOffset, size_t *outRecordSize)
272 {
273   char buffer[16];
274   size_t readSize;
275   int status = cdiInputFile_read(me->file, gribFileOffset, sizeof(buffer), &readSize, buffer);
276   if(status != CDI_NOERR && status != CDI_EEOF) return status;
277   if(readSize < sizeof(buffer)) return CDI_EEOF;
278   *outRecordSize = 0;
279   switch(buffer[7])
280     {
281       case 1:
282         *outRecordSize = decode24(&buffer[4]);
283         if(*outRecordSize & (1 << 23))
284           {
285             *outRecordSize = 120*(*outRecordSize & ((1 << 23) - 1));    //Rescaling for long records.
286             //The corresponding code in cgribexlib.c:4532-4570: is much more complicated
287             //due to the fact that it subtracts the padding bytes that are inserted after section 4.
288             //However, we are only interested in the total size of data we need to read here,
289             //so we can ignore the presence of some padding bytes.
290           }
291         return CDI_NOERR;
292 
293       case 2:
294         *outRecordSize =  decode64(&buffer[8]);
295         return CDI_NOERR;
296 
297       default:
298         return CDI_EUFTYPE;
299     }
300 }
301 
302 #if 0
303 static void hexdump(void *data, size_t size)
304 {
305   unsigned char *charData = data;
306   for(size_t offset = 0; offset < size; )
307     {
308       printf("%016zx:", offset);
309       for(size_t i = 0; i < 64 && offset < size; i++, offset++)
310         {
311           if((i & 63) && !(i & 15)) printf(" |");
312           if((i & 15) && !(i & 3)) printf("  ");
313           printf(" %02x", charData[offset]);
314         }
315       printf("\n");
316     }
317 }
318 #endif
319 
320 //Read a record into memory and wrap it in a grib_handle.
321 //XXX: I have omitted checking for szip compression as it is done in grbReadVarDP() & friends since that appears to be a non-standard extension of the GRIB1 standard: bit 1 in octet 14 of the binary data section which is used to signal szip compressio is defined to be reserved in the standard. As such, it seems prudent not to support this and to encourage people with such szip compressed files to switch to the GRIB2/JPEG2000 format. However, in the case that this reasoning is wrong, this function is probably the place to add the check for zsip compression.
readMessage(CdiGribIterator * me)322 static int readMessage(CdiGribIterator *me)
323 {
324   //Destroy the old grib_handle.
325   if(me->gribHandle) grib_handle_delete(me->gribHandle), me->gribHandle = NULL;
326   me->fileOffset += (off_t)me->curRecordSize;
327 
328   //Find the next record and determine its size.
329   ssize_t gribFileOffset = scanToGribMarker(me);
330   int result = CDI_EEOF;
331   if(gribFileOffset < 0) goto fail;
332   result = getRecordSize(me, gribFileOffset, &me->curRecordSize);
333   if(result) goto fail;
334 
335   //Load the whole record into our buffer and create a grib_handle for it.
336   cdiGribIterator_ensureBuffer(me, me->curRecordSize);
337   result = cdiInputFile_read(me->file, gribFileOffset, me->curRecordSize, NULL, me->gribBuffer);
338   if(result) goto fail;
339   me->gribHandle = grib_handle_new_from_message(NULL, me->gribBuffer, me->curRecordSize);
340   result = CDI_EUFSTRUCT;
341   if(!me->gribHandle) goto fail;
342 
343   return CDI_NOERR;
344 
345 fail:
346   me->curRecordSize = 0;        //This ensures that we won't jump to an uncontrolled file position if cdiGribIterator_nextField() is called another time after it has returned an error.
347   return result;
348 }
349 
cdiGribIterator_nextField(CdiIterator * super)350 int cdiGribIterator_nextField(CdiIterator *super)
351 {
352   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
353 
354   if(super->gridId != CDI_UNDEFID) gridDestroy(super->gridId), super->gridId = CDI_UNDEFID;
355 
356   //Get the next GRIB message into our buffer.
357   int result = readMessage(me);
358   if(result) return result;
359 
360   //Get the metadata that's published as variables in the base class.
361   super->datatype = gribGetDatatype(me->gribHandle);
362   super->timesteptype = gribapiGetTsteptype(me->gribHandle);
363   cdiDecodeParam(gribapiGetParam(me->gribHandle), &super->param.number, &super->param.category, &super->param.discipline);
364   grid_t grid;
365   gribapiGetGrid(me->gribHandle, &grid);
366   super->gridId = gridGenerate(&grid);
367 
368   return CDI_NOERR;
369 }
370 
cdiGribIterator_inqTime(CdiIterator * super,CdiTimeType timeType)371 char *cdiGribIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
372 {
373   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
374   return gribMakeTimeString(me->gribHandle, timeType);
375 }
376 
cdiGribIterator_levelType(CdiIterator * super,int levelSelector,char ** outName,char ** outLongName,char ** outStdName,char ** outUnit)377 int cdiGribIterator_levelType(CdiIterator *super, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
378 {
379   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
380 
381   //First determine the zaxis type corresponding to the given level.
382   int zaxisType = ZAXIS_GENERIC;
383   if(gribEditionNumber(me->gribHandle) <= 1)
384     {
385       int levelType = (int)gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", 255);
386       if(levelSelector && !isGrib1DualLevel(levelType)) levelType = 255;
387       zaxisType = grib1ltypeToZaxisType(levelType);
388     }
389   else
390     {
391       int levelType = (int)gribGetLongDefault(me->gribHandle, levelSelector ? "typeOfSecondFixedSurface" : "typeOfFirstFixedSurface", 255);
392       zaxisType = grib2ltypeToZaxisType(levelType);
393     }
394 
395   //Then lookup the requested names.
396   const char *name, *longName, *stdName, *unit;
397   zaxisGetTypeDescription(zaxisType, NULL, &name, &longName, &stdName, &unit);
398   if(outName) *outName = strdup(name);
399   if(outLongName) *outLongName = strdup(longName);
400   if(outStdName) *outStdName = strdup(stdName);
401   if(outUnit) *outUnit = strdup(unit);
402 
403   return zaxisType;
404 }
405 
logicalLevelValue2(long gribType,long storedValue,long power)406 static double logicalLevelValue2(long gribType, long storedValue, long power)
407 {
408   double factor = 1;
409   assert(power >= 0);
410   while(power--) factor *= 10;      //this is precise up to factor == 22.
411   switch(gribType)
412     {
413       case GRIB2_LTYPE_LANDDEPTH:
414       case GRIB2_LTYPE_ISOBARIC:
415       case GRIB2_LTYPE_SIGMA:
416         return (double)storedValue * (1000.0/factor);      //The evaluation order allows the factors of ten to cancel out before rounding.
417 
418       case 255:
419         return 0;
420 
421       default:
422         return (double)storedValue/factor;
423     }
424 }
425 
426 //The output values must be preinitialized, this function does not always write them.
readLevel2(grib_handle * gribHandle,const char * levelTypeKey,const char * powerKey,const char * valueKey,double * outValue1,double * outValue2)427 static int readLevel2(grib_handle *gribHandle, const char *levelTypeKey, const char *powerKey, const char *valueKey, double *outValue1, double *outValue2)
428 {
429   assert(levelTypeKey && powerKey && valueKey && outValue1 && outValue2);
430 
431   long levelType = gribGetLongDefault(gribHandle, levelTypeKey, 255);   //1 byte
432   switch(levelType)
433     {
434       case 255: break;
435 
436       case 105: case 113:
437         {
438           unsigned long value = (unsigned long)gribGetLongDefault(gribHandle, valueKey, 0);
439           unsigned long coordinateCount = (unsigned long)gribGetLongDefault(gribHandle, "numberOfCoordinatesValues", 0);
440           if(value >= coordinateCount/2)
441             {
442               Error("Invalid level coordinate: Level has the hybrid coordinate index %lu, but only %lu coordinate pairs are present.", value, coordinateCount/2);
443               return CDI_EUFSTRUCT;
444             }
445           int status;
446           //XXX: I'm not 100% sure about how the coordinate pairs are stored in the file.
447           //     I'm assuming an array of pairs due to the example code in grib_api-1.12.3/examples/F90/set_pv.f90, but that may be wrong.
448           if((status = grib_get_double_element(gribHandle, "pv", (int)value*2    , outValue1))) return status;
449           if((status = grib_get_double_element(gribHandle, "pv", (int)value*2 + 1, outValue2))) return status;
450           break;
451         }
452 
453       default:
454         {
455           long power = 255 & gribGetLongDefault(gribHandle, powerKey, 0);  //1 byte
456           if(power == 255) power = 0;
457           long value = gribGetLongDefault(gribHandle, valueKey, 0);   //4 bytes
458           *outValue1 = logicalLevelValue2(levelType, value, power);
459         }
460     }
461   return CDI_NOERR;
462 }
463 
cdiGribIterator_level(CdiIterator * super,int levelSelector,double * outValue1,double * outValue2)464 int cdiGribIterator_level(CdiIterator *super, int levelSelector, double *outValue1, double *outValue2)
465 {
466   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
467   double trash;
468   if(!outValue1) outValue1 = &trash;
469   if(!outValue2) outValue2 = &trash;
470   *outValue1 = *outValue2 = 0;
471 
472   if(gribEditionNumber(me->gribHandle) > 1)
473     {
474       if(levelSelector)
475         {
476           return readLevel2(me->gribHandle, "typeOfFirstFixedSurface", "scaleFactorOfFirstFixedSurface", "scaledValueOfFirstFixedSurface", outValue1, outValue2);
477         }
478       else
479         {
480           return readLevel2(me->gribHandle, "typeOfSecondFixedSurface", "scaleFactorOfSecondFixedSurface", "scaledValueOfSecondFixedSurface", outValue1, outValue2);
481         }
482     }
483   else
484     {
485       long levelType = (uint8_t)gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", -1);    //1 byte
486       if(levelType == 255)
487         {}
488       else if(isGrib1DualLevel((int)levelType))
489         {
490           *outValue1 = (double)(gribGetLongDefault(me->gribHandle, (levelSelector ? "bottomLevel" : "topLevel"), 0));
491         }
492       else if(levelType == 100)
493         {
494           *outValue1 = 100 * (double)(gribGetLongDefault(me->gribHandle, "level", 0));        //2 bytes
495         }
496       else
497         {
498           *outValue1 = (double)(gribGetLongDefault(me->gribHandle, "level", 0));        //2 bytes
499         }
500     }
501   return CDI_NOERR;
502 }
503 
cdiGribIterator_zaxisUuid(CdiIterator * super,int * outVgridNumber,int * outLevelCount,unsigned char outUuid[CDI_UUID_SIZE])504 int cdiGribIterator_zaxisUuid(CdiIterator *super, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE])
505 {
506   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
507 
508   if(outVgridNumber)
509     {
510       long temp;
511       if(grib_get_long(me->gribHandle, "numberOfVGridUsed", &temp)) return CDI_EINVAL;
512       *outVgridNumber = (int)temp;
513     }
514   if(outLevelCount)
515     {
516       long temp;
517       if(grib_get_long(me->gribHandle, "nlev", &temp)) return CDI_EINVAL;
518       *outLevelCount = (int)temp;
519     }
520   if(outUuid)
521     {
522       size_t size = CDI_UUID_SIZE;
523       if(grib_get_bytes(me->gribHandle, "uuidOfVGrid", outUuid, &size)) return CDI_EINVAL;
524       if(size != CDI_UUID_SIZE) return CDI_EUFSTRUCT;
525     }
526 
527   return CDI_NOERR;
528 }
529 
cdiGribIterator_inqTile(CdiIterator * super,int * outTileIndex,int * outTileAttribute)530 int cdiGribIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
531 {
532   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
533   int trash;
534   if(!outTileIndex) outTileIndex = &trash;
535   if(!outTileAttribute) outTileAttribute = &trash;
536 
537   //Get the values if possible.
538   int error = CDI_NOERR;
539   long value;
540   if(grib_get_long(me->gribHandle, "tileIndex", &value)) error = CDI_EINVAL;
541   *outTileIndex = (int)value;
542   if(grib_get_long(me->gribHandle, "tileAttribute", &value)) error = CDI_EINVAL;
543   *outTileAttribute = (int)value;
544 
545   //Ensure defined return values in case of failure.
546   if(error) *outTileIndex = *outTileAttribute = -1;
547   return error;
548 }
549 
cdiGribIterator_inqTileCount(CdiIterator * super,int * outTileCount,int * outTileAttributeCount)550 int cdiGribIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
551 {
552   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
553   int trash;
554   if(!outTileCount) outTileCount = &trash;
555   if(!outTileAttributeCount) outTileAttributeCount = &trash;
556 
557   //Get the values if possible.
558   int error = CDI_NOERR;
559   long value;
560   if(grib_get_long(me->gribHandle, "numberOfTiles", &value)) error = CDI_EINVAL;
561   *outTileCount = (int)value;
562   if(grib_get_long(me->gribHandle, "numberOfTileAttributes", &value)) error = CDI_EINVAL;
563   *outTileAttributeCount = (int)value;
564 
565   //Ensure defined return values in case of failure.
566   if(error) *outTileCount = *outTileAttributeCount = 0;
567   return error;
568 }
569 
cdiGribIterator_copyVariableName(CdiIterator * super)570 char *cdiGribIterator_copyVariableName(CdiIterator *super)
571 {
572   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
573   return gribCopyString(me->gribHandle, "shortName");
574 }
575 
cdiGribIterator_readField(CdiIterator * super,double * buffer,size_t * nmiss)576 void cdiGribIterator_readField(CdiIterator *super, double *buffer, size_t *nmiss)
577 {
578   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
579 
580   GRIB_CHECK(my_grib_set_double(me->gribHandle, "missingValue", CDI_Default_Missval), 0);
581   gribGetDoubleArray(me->gribHandle, "values", buffer);
582   long gridType = gribGetLong(me->gribHandle, "gridDefinitionTemplateNumber");
583   if (nmiss)
584     {
585       // The condition excludes harmonic data.
586       *nmiss = (gridType >= 50 && gridType <= 53) ? (size_t)0 : (size_t)gribGetLong(me->gribHandle, "numberOfMissing");
587     }
588 }
589 
cdiGribIterator_readFieldF(CdiIterator * super,float * buffer,size_t * nmiss)590 void cdiGribIterator_readFieldF(CdiIterator *super, float *buffer, size_t *nmiss)
591 {
592   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
593 
594   size_t valueCount = gribGetArraySize(me->gribHandle, "values");
595   double *temp = (double *) Malloc(valueCount*sizeof(*temp));
596   cdiGribIterator_readField(super, temp, nmiss);
597   for(size_t i = valueCount; i--; ) buffer[i] = (float)temp[i];
598   Free(temp);
599 }
600 #endif
601 
602 /*
603 @Function cdiGribIterator_delete
604 @Title Dispose off a CdiGribIterator instance.
605 
606 @Prototype void cdiGribIterator_delete(CdiGribIterator *me)
607 @Parameter
608     @item me The iterator to delete.
609 
610 @Description
611     Combined destructor and deallocator. Make sure to match every call to cdiGribIterator_clone() with a call to this function.
612 */
cdiGribIterator_delete(CdiGribIterator * me)613 void cdiGribIterator_delete(CdiGribIterator *me)
614 {
615 #ifdef HAVE_LIBGRIB_API
616   if(me) cdiGribIterator_condestruct(me, NULL, 0);
617 #else
618   if (me)
619     xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
620 #endif
621 }
622 
623 
624 ////////////////////////////////////////////////////////////////////////////////////////////////////
625 // callthroughs to provide direct access to the grib keys //////////////////////////////////////////
626 ////////////////////////////////////////////////////////////////////////////////////////////////////
627 
628 /*
629 @Function cdiGribIterator_inqEdition
630 @Title Get the version of the GRIB standard that is used
631 
632 @Prototype int cdiGribIterator_inqEdition(CdiGribIterator *me)
633 @Parameter
634     @item me The iterator to operate on.
635 
636 @Result The GRIB version.
637 
638 @Description
639     Returns the version of the file format.
640 */
cdiGribIterator_inqEdition(CdiGribIterator * me)641 int cdiGribIterator_inqEdition(CdiGribIterator *me)
642 {
643 #ifdef HAVE_LIBGRIB_API
644   return (int)gribEditionNumber(me->gribHandle);
645 #else
646   (void)me;
647   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
648   return -4;
649 #endif
650 }
651 
652 /*
653 @Function cdiGribIterator_getLong
654 @Title Access to grib_get_long()
655 
656 @Prototype int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *result)
657 @Parameter
658     @item me The iterator to operate on.
659     @item ... The arguments to the underlying GRIB-API function.
660 
661 @Result An error code.
662 
663 @Description
664     Callthrough to grib_get_long().
665 */
cdiGribIterator_getLong(CdiGribIterator * me,const char * key,long * result)666 int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *result)
667 {
668 #ifdef HAVE_LIBGRIB_API
669   return grib_get_long(me->gribHandle, key, result);
670 #else
671   (void)me;
672   (void)key;
673   (void)result;
674   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
675   return -4;
676 #endif
677 }
678 
679 /*
680 @Function cdiGribIterator_getLength
681 @Title Access to grib_get_length()
682 
683 @Prototype int cdiGribIterator_getLength(CdiGribIterator *me, const char *key, size_t *result)
684 @Parameter
685     @item me The iterator to operate on.
686     @item ... The arguments to the underlying GRIB-API function.
687 
688 @Result An error code.
689 
690 @Description
691     Callthrough to grib_get_length().
692 */
cdiGribIterator_getLength(CdiGribIterator * me,const char * key,size_t * result)693 int cdiGribIterator_getLength(CdiGribIterator *me, const char *key, size_t *result)
694 {
695 #ifdef HAVE_LIBGRIB_API
696 #ifdef HAVE_GRIB_GET_LENGTH
697   return grib_get_length(me->gribHandle, key, result);
698 #else
699   (void)me;
700   (void)key;
701   (void)result;
702   Error("grib_get_length() is not available, so cdiGribIterator_getLength() can't be used");
703   return -1;
704 #endif
705 #else
706   (void)me;
707   (void)key;
708   (void)result;
709   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
710   return -4;
711 #endif
712 }
713 
714 /*
715 @Function cdiGribIterator_getString
716 @Title Access to grib_get_string()
717 
718 @Prototype int cdiGribIterator_getString(CdiGribIterator *me, const char *key, char *result, size_t *length)
719 @Parameter
720     @item me The iterator to operate on.
721     @item ... The arguments to the underlying GRIB-API function.
722 
723 @Result An error code.
724 
725 @Description
726     Callthrough to grib_get_string().
727 */
cdiGribIterator_getString(CdiGribIterator * me,const char * key,char * result,size_t * length)728 int cdiGribIterator_getString(CdiGribIterator *me, const char *key, char *result, size_t *length)
729 {
730 #ifdef HAVE_LIBGRIB_API
731   return grib_get_string(me->gribHandle, key, result, length);
732 #else
733   (void)me;
734   (void)key;
735   (void)result;
736   (void)length;
737   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
738   return -4;
739 #endif
740 }
741 
742 /*
743 @Function cdiGribIterator_inqLongValue
744 @Title Get the value of a GRIB-API key as a long
745 
746 @Prototype long cdiGribIterator_inqLongValue(CdiGribIterator *me, const char *key)
747 @Parameter
748     @item me The iterator to operate on.
749     @item key The GRIB-API key to retrieve.
750 
751 @Result The value of the key.
752 
753 @Description
754     Use this to fetch a grib value if you are certain that the given key must be present.
755     This will abort the process if the key cannot be retrieved.
756 */
cdiGribIterator_inqLongValue(CdiGribIterator * me,const char * key)757 long cdiGribIterator_inqLongValue(CdiGribIterator *me, const char *key)
758 {
759 #ifdef HAVE_LIBGRIB_API
760   return gribGetLong(me->gribHandle, key);
761 #else
762   (void)me;
763   (void)key;
764   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
765   return -4;
766 #endif
767 }
768 
769 /*
770 @Function cdiGribIterator_inqLongDefaultValue
771 @Title Get the value of a GRIB-API key as a long
772 
773 @Prototype long cdiGribIterator_inqLongDefaultValue(CdiGribIterator *me, const char *key, long defaultValue)
774 @Parameter
775     @item me The iterator to operate on.
776     @item key The GRIB-API key to retrieve.
777     @item defaultValue The value to return if the key is not present.
778 
779 @Result The value of the key or the given default value.
780 
781 @Description
782     Use this if you can handle failure to fetch the key by supplying a default value.
783     This function cannot fail.
784 */
cdiGribIterator_inqLongDefaultValue(CdiGribIterator * me,const char * key,long defaultValue)785 long cdiGribIterator_inqLongDefaultValue(CdiGribIterator *me, const char *key, long defaultValue)
786 {
787 #ifdef HAVE_LIBGRIB_API
788   return gribGetLongDefault(me->gribHandle, key, defaultValue);
789 #else
790   (void)me;
791   (void)key;
792   (void)defaultValue;
793   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
794   return -4;
795 #endif
796 }
797 
798 /*
799 @Function cdiGribIterator_inqStringValue
800 @Title Safely retrieve a GRIB-API key with a string value
801 
802 @Prototype char *cdiGribIterator_inqStringValue(CdiGribIterator *me, const char *key)
803 @Parameter
804     @item me The iterator to operate on.
805     @item key The GRIB-API key to retrieve.
806 
807 @Result A malloc'ed string or NULL.
808 
809 @Description
810     This will first call grib_get_length() to inquire the actual size of the string,
811     allocate memory accordingly, call grib_get_string(), and return the pointer to the new string.
812     Returns NULL on failure.
813 */
cdiGribIterator_inqStringValue(CdiGribIterator * me,const char * key)814 char *cdiGribIterator_inqStringValue(CdiGribIterator *me, const char *key)
815 {
816 #ifdef HAVE_LIBGRIB_API
817   return gribCopyString(me->gribHandle, key);
818 #else
819   (void)me;
820   (void)key;
821   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
822   return NULL;
823 #endif
824 }
825 
826 /*
827 @Function cdiGribIterator_getDouble
828 @Title Access to grib_get_double()
829 
830 @Prototype int cdiGribIterator_getDouble(CdiGribIterator *me, const char *key, double *result)
831 @Parameter
832     @item me The iterator to operate on.
833     @item ... The arguments to the underlying GRIB-API function.
834 
835 @Result An error code.
836 
837 @Description
838     Callthrough to grib_get_double().
839 */
cdiGribIterator_getDouble(CdiGribIterator * me,const char * key,double * result)840 int cdiGribIterator_getDouble(CdiGribIterator *me, const char *key, double *result)
841 {
842 #ifdef HAVE_LIBGRIB_API
843   return grib_get_double(me->gribHandle, key, result);
844 #else
845   (void)me;
846   (void)key;
847   (void)result;
848   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
849   return -4;
850 #endif
851 }
852 
853 /*
854 @Function cdiGribIterator_getSize
855 @Title Access to grib_get_size()
856 
857 @Prototype int cdiGribIterator_getSize(CdiGribIterator *me, const char *key, size_t *result)
858 @Parameter
859     @item me The iterator to operate on.
860     @item ... The arguments to the underlying GRIB-API function.
861 
862 @Result An error code.
863 
864 @Description
865     Callthrough to grib_get_size().
866 */
cdiGribIterator_getSize(CdiGribIterator * me,const char * key,size_t * result)867 int cdiGribIterator_getSize(CdiGribIterator *me, const char *key, size_t *result)
868 {
869 #ifdef HAVE_LIBGRIB_API
870   return grib_get_size(me->gribHandle, key, result);
871 #else
872   (void)me;
873   (void)key;
874   (void)result;
875   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
876   return -4;
877 #endif
878 }
879 
880 /*
881 @Function cdiGribIterator_getLongArray
882 @Title Access to grib_get_long_array()
883 
884 @Prototype int cdiGribIterator_getLongArray(CdiGribIterator *me, const char *key, long *result, size_t *size)
885 @Parameter
886     @item me The iterator to operate on.
887     @item ... The arguments to the underlying GRIB-API function.
888 
889 @Result An error code.
890 
891 @Description
892     Callthrough to grib_get_long_array().
893 */
cdiGribIterator_getLongArray(CdiGribIterator * me,const char * key,long * result,size_t * size)894 int cdiGribIterator_getLongArray(CdiGribIterator *me, const char *key, long *result, size_t *size)
895 {
896 #ifdef HAVE_LIBGRIB_API
897   return grib_get_long_array(me->gribHandle, key, result, size);
898 #else
899   (void)me;
900   (void)key;
901   (void)result;
902   (void)size;
903   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
904   return -4;
905 #endif
906 }
907 
908 /*
909 @Function cdiGribIterator_getDoubleArray
910 @Title Access to grib_get_double_array()
911 
912 @Prototype int cdiGribIterator_getDoubleArray(CdiGribIterator *me, const char *key, double *result, size_t *size)
913 @Parameter
914     @item me The iterator to operate on.
915     @item ... The arguments to the underlying GRIB-API function.
916 
917 @Result An error code.
918 
919 @Description
920     Callthrough to grib_get_double_array().
921 */
cdiGribIterator_getDoubleArray(CdiGribIterator * me,const char * key,double * result,size_t * size)922 int cdiGribIterator_getDoubleArray(CdiGribIterator *me, const char *key, double *result, size_t *size)
923 {
924 #ifdef HAVE_LIBGRIB_API
925   return grib_get_double_array(me->gribHandle, key, result, size);
926 #else
927   (void)me;
928   (void)key;
929   (void)result;
930   (void)size;
931   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
932   return -4;
933 #endif
934 }
935 
936 /*
937 @Function cdiGribIterator_inqDoubleValue
938 @Title Get the value of a GRIB-API key as a double
939 
940 @Prototype double cdiGribIterator_inqDoubleValue(CdiGribIterator *me, const char *key)
941 @Parameter
942     @item me The iterator to operate on.
943     @item key The GRIB-API key to retrieve.
944 
945 @Result The value of the key.
946 
947 @Description
948     Use this to fetch a grib value if you are certain that the given key must be present.
949     This will abort the process if the key cannot be retrieved.
950 */
cdiGribIterator_inqDoubleValue(CdiGribIterator * me,const char * key)951 double cdiGribIterator_inqDoubleValue(CdiGribIterator *me, const char *key)
952 {
953 #ifdef HAVE_LIBGRIB_API
954   return gribGetDouble(me->gribHandle, key);
955 #else
956   (void)me;
957   (void)key;
958   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
959   return -4;
960 #endif
961 }
962 
963 /*
964 @Function cdiGribIterator_inqDoubleDefaultValue
965 @Title Get the value of a GRIB-API key as a double
966 
967 @Prototype double cdiGribIterator_inqDoubleDefaultValue(CdiGribIterator *me, const char *key, double defaultValue)
968 @Parameter
969     @item me The iterator to operate on.
970     @item key The GRIB-API key to retrieve.
971     @item defaultValue The value to return if the key is not present.
972 
973 @Result The value of the key or the given default value.
974 
975 @Description
976     Use this if you can handle failure to fetch the key by supplying a default value.
977     This function cannot fail.
978 */
cdiGribIterator_inqDoubleDefaultValue(CdiGribIterator * me,const char * key,double defaultValue)979 double cdiGribIterator_inqDoubleDefaultValue(CdiGribIterator *me, const char *key, double defaultValue)
980 {
981 #ifdef HAVE_LIBGRIB_API
982   return gribGetDoubleDefault(me->gribHandle, key, defaultValue);
983 #else
984   (void)me;
985   (void)key;
986   (void)defaultValue;
987   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
988   return -4;
989 #endif
990 }
991 
992 /*
993  * Local Variables:
994  * c-file-style: "Java"
995  * c-basic-offset: 2
996  * indent-tabs-mode: nil
997  * show-trailing-whitespace: t
998  * require-trailing-newline: t
999  * End:
1000  */
1001