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