iterator_grib.c 31.6 KB
Newer Older
1
2
#include "iterator_grib.h"

3
#include "cdi.h"
4
5
6
7
8
9
10
11
12
13
#include "cdi_int.h"
#include "cgribex.h"
#include "dmemory.h"
#include "error.h"
#include "gribapi.h"
#include "gribapi_utilities.h"
#include "stream_grb.h"
#include "zaxis.h"

#include <assert.h>
14
#include <limits.h>
15
16
17
18
#include <stdlib.h>
#include <string.h>


19
20
#ifdef HAVE_LIBGRIB_API

21
22
23
struct CdiGribIterator {
  CdiIterator super;

24
  CdiInputFile *file;
25
  off_t fileOffset;
26
  unsigned char *gribBuffer;
27
28
  size_t bufferSize, curRecordSize;
#ifdef HAVE_LIBGRIB_API
29
  grib_handle *gribHandle;
30
#else
31
  void *gribHandle;
32
33
34
35
36
37
38
39
#endif
};

CdiIterator *cdiGribIterator_getSuper(CdiGribIterator *me)
{
  return &me->super;
}

40
41
42
43
44
//Since the error handling in constructors is usually very closely related to the workings of a destructor,
//this function combines both functions in one, using a centralized exit.
//The mode of operation depends on whether me is a NULL pointer on entry:
//If it is NULL, a new object is allocated and constructed, which is returned if construction is successful.
//If a non-NULL pointer is passed in, the object is destructed and NULL is returned. In this case, the other arguments are ignored.
45
static CdiGribIterator *cdiGribIterator_condestruct(CdiGribIterator *me, const char *path, int filetype)
46
{
47
#define super() (&me->super)
48
  if(me) goto destruct;
49
  me = (CdiGribIterator *) Malloc(sizeof(*me));
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
  baseIterConstruct(super(), filetype);

  me->file = cdiInputFile_make(path);
  if(!me->file) goto destructSuper;
  me->fileOffset = 0;
  me->gribHandle = NULL;
  me->gribBuffer = NULL;
  me->bufferSize = me->curRecordSize = 0;
  me->super.gridId = CDI_UNDEFID;

  goto success;

// ^        constructor code        ^
// |                                |
// v destructor/error-cleanup code  v

destruct:
  if(me->super.gridId != CDI_UNDEFID) gridDestroy(me->super.gridId);
68
  if(me->gribHandle) grib_handle_delete((struct grib_handle *)me->gribHandle);
69
  Free(me->gribBuffer);
70
71
72
  cdiRefObject_release(&me->file->super);
destructSuper:
  baseIterDestruct(super());
73
  Free(me);
74
75
76
77
  me = NULL;

success:
  return me;
78
#undef super
79
80
}

81
CdiIterator *cdiGribIterator_new(const char *path, int filetype)
82
{
83
  return &cdiGribIterator_condestruct(NULL, path, filetype)->super;
84
85
}

86
CdiGribIterator *cdiGribIterator_makeClone(CdiIterator *super)
87
{
88
  CdiGribIterator *me = (CdiGribIterator*)super;
89
90

  //Allocate memory and copy data. (operations that may fail)
91
  CdiGribIterator *result = (struct CdiGribIterator *) Malloc(sizeof(*result));
92
  if(!result) goto fail;
93
94
95
96
97
98
99
100

  result->file = me->file;
  result->fileOffset = me->fileOffset;
  result->gribBuffer = NULL;
  result->bufferSize = me->bufferSize;
  result->curRecordSize = me->curRecordSize;
  result->gribHandle = NULL;

101
102
  if(me->gribBuffer)
    {
103
      result->gribBuffer = (unsigned char *) Malloc(me->bufferSize);
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
      if(!result->gribBuffer) goto freeResult;
      memcpy(result->gribBuffer, me->gribBuffer, me->curRecordSize);
    }
  if(me->gribHandle)
    {
      result->gribHandle = grib_handle_new_from_message(NULL, result->gribBuffer, result->curRecordSize);
      if(!result->gribHandle) goto freeBuffer;
    }
  if(super->gridId != CDI_UNDEFID)
    {
      result->super.gridId = gridDuplicate(super->gridId);
      if(result->super.gridId == CDI_UNDEFID) goto deleteGribHandle;
    }

  //Finish construction. (operations that cannot fail)
  baseIterConstruct(&result->super, super->filetype);
  result->super.datatype = super->datatype;
  result->super.timesteptype = super->timesteptype;
  result->super.param = super->param;
  cdiRefObject_retain(&result->file->super);

  return result;

  //Error handling.
deleteGribHandle:
129
  if(result->gribHandle) grib_handle_delete(result->gribHandle);
130
freeBuffer:
131
  Free(result->gribBuffer);
132
freeResult:
133
  Free(result);
134
135
136
137
fail:
  return NULL;
}

138
char *cdiGribIterator_serialize(CdiIterator *super)
139
{
140
  CdiGribIterator *me = (CdiGribIterator*)super;
141

142
143
144
  const char *path = cdiInputFile_getPath(me->file);
  char *escapedPath = cdiEscapeSpaces(path);
  char *result = (char *) Malloc(strlen(escapedPath) + 3 * sizeof(int) * CHAR_BIT/8);
145
  sprintf(result, "%s %zu", escapedPath, me->fileOffset);
146
  Free(escapedPath);
147
148
  return result;
}
149

150

151
CdiGribIterator *cdiGribIterator_deserialize(const char *description)
152
{
153
154
  char *path;
  CdiGribIterator *me = (CdiGribIterator *) Malloc(sizeof(*me));
155
156
157
158
159
160
161
162
163
  if(!me) goto fail;

  description = baseIter_constructFromString(&me->super, description);

  while(*description == ' ') description++;
  path = cdiUnescapeSpaces(description, &description);
  if(!path) goto destructSuper;

  me->file = cdiInputFile_make(path);
164
  Free(path);
165
166
167
  if(!me->file) goto destructSuper;

  {
168
    const char *savedStart = description;
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
    long long decodedOffset = strtoll(description, (char**)&description, 0);    //The cast is a workaround for the wrong signature of strtoll() (it should have been `long long strtoll(const char*, const char**, int)`, not `long long strtoll(const char*, char**, int)`.
    me->fileOffset = (off_t)decodedOffset;
    if(savedStart == description) goto closeFile;
    if((unsigned long long)decodedOffset > (unsigned long long)me->fileOffset) goto closeFile;
  }

  me->gribBuffer = NULL;
  me->bufferSize = me->curRecordSize = 0;
  me->gribHandle = NULL;
  me->super.gridId = CDI_UNDEFID;
  if(me->super.isAdvanced && cdiGribIterator_nextField(&me->super)) goto closeFile;

  return me;


closeFile:
  cdiRefObject_release(&me->file->super);
destructSuper:
  baseIterDestruct(&me->super);
188
  Free(me);
189
190
191
192
fail:
  return NULL;
}

193
static void cdiGribIterator_ensureBuffer(CdiGribIterator *me, size_t requiredSize)
194
195
196
197
198
{
  if(me->bufferSize < requiredSize)
    {
      me->bufferSize *= 2;
      if(me->bufferSize < requiredSize) me->bufferSize = requiredSize;
199
      me->gribBuffer = (unsigned char *) Realloc(me->gribBuffer, me->bufferSize);
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    }
}

static bool isGrib1DualLevel(int levelType)
{
  switch(levelType)
    {
      case 101: case 104: case 106: case 108: case 110: case 112:
      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.
        return true;
      default:
        return false;
    }
}

215
static const unsigned char *positionOfGribMarker(const unsigned char *data, size_t size)
216
{
217
  for(const unsigned char *currentPosition = data, *end = data + size; currentPosition < end; currentPosition++)
218
    {
219
      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.
220
221
222
223
224
225
226
227
      if(!currentPosition) return NULL;
      if(!strncmp((const char*)currentPosition, "GRIB", 4)) return currentPosition;
    }
  return NULL;
}

//This clobbers the contents of the gribBuffer!
//Returns the file offset of the next 'GRIB' marker.
228
static ssize_t scanToGribMarker(CdiGribIterator *me)
229
230
231
232
233
234
235
236
237
{
  cdiGribIterator_ensureBuffer(me, 8*1024);
  const size_t kMaxScanSize = 16*1024*1024;
  for(size_t scannedBytes = 0, scanSize; scannedBytes < kMaxScanSize; scannedBytes += scanSize)
    {
      //Load a chunk of data into our buffer.
      scanSize = me->bufferSize;
      if(scannedBytes + scanSize > kMaxScanSize) scanSize = kMaxScanSize - scannedBytes;
      assert(scanSize <= me->bufferSize);
Thomas Jahns's avatar
Thomas Jahns committed
238
      int status = cdiInputFile_read(me->file, me->fileOffset + (off_t)scannedBytes, scanSize, &scanSize, me->gribBuffer);
239
240
      if(status != CDI_NOERR && status != CDI_EEOF) return status;

241
      const unsigned char *startPosition = positionOfGribMarker(me->gribBuffer, scanSize);
242
243
      if(startPosition)
        {
Thomas Jahns's avatar
Thomas Jahns committed
244
          return (ssize_t)(me->fileOffset + (off_t)scannedBytes + (off_t)(startPosition - me->gribBuffer));
245
246
247
248
249
        }

      //Get the offset for the next iteration if there is a next iteration.
      scanSize -= 3;        //so that we won't miss a 'GRIB' sequence that happens to be cut off
      scannedBytes += scanSize;
Thomas Jahns's avatar
Thomas Jahns committed
250
      scannedBytes &= ~(size_t)0xf; //make 16 bytes aligned
251
252
253
254
    }
  return -1;
}

255
static unsigned decode24(void *beData)
256
{
257
  unsigned char *bytes = (unsigned char *)beData;
258
259
260
  return ((unsigned)bytes[0] << 16) + ((unsigned)bytes[1] << 8) + (unsigned)bytes[2];
}

261
static uint64_t decode64(void *beData)
262
{
263
  unsigned char *bytes = (unsigned char *)beData;
264
265
266
267
268
269
  uint64_t result = 0;
  for(size_t i = 0; i < 8; i++) result = (result << 8) + bytes[i];
  return result;
}

//Determine the size of the GRIB record that begins at the given file offset.
270
static int getRecordSize(CdiGribIterator *me, off_t gribFileOffset, size_t *outRecordSize)
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
{
  char buffer[16];
  size_t readSize;
  int status = cdiInputFile_read(me->file, gribFileOffset, sizeof(buffer), &readSize, buffer);
  if(status != CDI_NOERR && status != CDI_EEOF) return status;
  if(readSize < sizeof(buffer)) return CDI_EEOF;
  *outRecordSize = 0;
  switch(buffer[7])
    {
      case 1:
        *outRecordSize = decode24(&buffer[4]);
        if(*outRecordSize & (1 << 23))
          {
            *outRecordSize = 120*(*outRecordSize & ((1 << 23) - 1));    //Rescaling for long records.
            //The corresponding code in cgribexlib.c:4532-4570: is much more complicated
            //due to the fact that it subtracts the padding bytes that are inserted after section 4.
            //However, we are only interested in the total size of data we need to read here,
            //so we can ignore the presence of some padding bytes.
          }
        return CDI_NOERR;

      case 2:
        *outRecordSize =  decode64(&buffer[8]);
        return CDI_NOERR;

      default:
        return CDI_EUFTYPE;
    }
}

#if 0
302
static void hexdump(void *data, size_t size)
303
{
304
  unsigned char *charData = data;
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
  for(size_t offset = 0; offset < size; )
    {
      printf("%016zx:", offset);
      for(size_t i = 0; i < 64 && offset < size; i++, offset++)
        {
          if((i & 63) && !(i & 15)) printf(" |");
          if((i & 15) && !(i & 3)) printf("  ");
          printf(" %02x", charData[offset]);
        }
      printf("\n");
    }
}
#endif

//Read a record into memory and wrap it in a grib_handle.
//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.
321
static int readMessage(CdiGribIterator *me)
322
323
{
  //Destroy the old grib_handle.
324
  if(me->gribHandle) grib_handle_delete(me->gribHandle), me->gribHandle = NULL;
Thomas Jahns's avatar
Thomas Jahns committed
325
  me->fileOffset += (off_t)me->curRecordSize;
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348

  //Find the next record and determine its size.
  ssize_t gribFileOffset = scanToGribMarker(me);
  int result = CDI_EEOF;
  if(gribFileOffset < 0) goto fail;
  result = getRecordSize(me, gribFileOffset, &me->curRecordSize);
  if(result) goto fail;

  //Load the whole record into our buffer and create a grib_handle for it.
  cdiGribIterator_ensureBuffer(me, me->curRecordSize);
  result = cdiInputFile_read(me->file, gribFileOffset, me->curRecordSize, NULL, me->gribBuffer);
  if(result) goto fail;
  me->gribHandle = grib_handle_new_from_message(NULL, me->gribBuffer, me->curRecordSize);
  result = CDI_EUFSTRUCT;
  if(!me->gribHandle) goto fail;

  return CDI_NOERR;

fail:
  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.
  return result;
}

349
int cdiGribIterator_nextField(CdiIterator *super)
350
{
351
  CdiGribIterator *me = (CdiGribIterator*)super;
352
353
354
355
356
357
358
359

  if(super->gridId != CDI_UNDEFID) gridDestroy(super->gridId), super->gridId = CDI_UNDEFID;

  //Get the next GRIB message into our buffer.
  int result = readMessage(me);
  if(result) return result;

  //Get the metadata that's published as variables in the base class.
360
361
362
  super->datatype = gribGetDatatype(me->gribHandle);
  super->timesteptype = gribapiGetTsteptype(me->gribHandle);
  cdiDecodeParam(gribapiGetParam(me->gribHandle), &super->param.number, &super->param.category, &super->param.discipline);
363
  grid_t grid;
364
  gribapiGetGrid(me->gribHandle, &grid);
365
366
367
368
369
  super->gridId = gridGenerate(&grid);

  return CDI_NOERR;
}

370
char *cdiGribIterator_inqTime(CdiIterator *super, bool getEndTime)
371
{
372
  CdiGribIterator *me = (CdiGribIterator*)super;
373
  return gribMakeTimeString(me->gribHandle, getEndTime);
374
375
}

376
int cdiGribIterator_levelType(CdiIterator *super, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
377
{
378
  CdiGribIterator *me = (CdiGribIterator*)super;
379
380
381

  //First determine the zaxis type corresponding to the given level.
  int zaxisType = ZAXIS_GENERIC;
382
  if(gribEditionNumber(me->gribHandle) <= 1)
383
    {
384
      int levelType = gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", 255);
385
386
387
388
389
      if(levelSelector && !isGrib1DualLevel(levelType)) levelType = 255;
      zaxisType = grib1ltypeToZaxisType(levelType);
    }
  else
    {
390
      int levelType = gribGetLongDefault(me->gribHandle, levelSelector ? "typeOfSecondFixedSurface" : "typeOfFirstFixedSurface", 255);
391
392
393
394
      zaxisType = grib2ltypeToZaxisType(levelType);
    }

  //Then lookup the requested names.
395
  const char *name, *longName, *stdName, *unit;
396
  zaxisGetTypeDescription(zaxisType, NULL, &name, &longName, &stdName, &unit);
397
398
399
400
  if(outName) *outName = strdup(name);
  if(outLongName) *outLongName = strdup(longName);
  if(outStdName) *outStdName = strdup(stdName);
  if(outUnit) *outUnit = strdup(unit);
401
402
403
404
405
406
407
408
409
410
411
412
413

  return zaxisType;
}

static double logicalLevelValue2(long gribType, long storedValue, long power)
{
  double factor = 1;
  while(power--) factor *= 10;      //this is precise up to factor == 22.
  switch(gribType)
    {
      case GRIB2_LTYPE_LANDDEPTH:
      case GRIB2_LTYPE_ISOBARIC:
      case GRIB2_LTYPE_SIGMA:
Thomas Jahns's avatar
Thomas Jahns committed
414
        return (double)storedValue * (1000.0/factor);      //The evaluation order allows the factors of ten to cancel out before rounding.
415
416
417
418
419

      case 255:
        return 0;

      default:
Thomas Jahns's avatar
Thomas Jahns committed
420
        return (double)storedValue/factor;
421
422
423
424
    }
}

//The output values must be preinitialized, this function does not always write them.
425
static int readLevel2(grib_handle *gribHandle, const char *levelTypeKey, const char *powerKey, const char *valueKey, double *outValue1, double *outValue2)
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
{
  assert(levelTypeKey && powerKey && valueKey && outValue1 && outValue2);

  long levelType = gribGetLongDefault(gribHandle, levelTypeKey, 255);   //1 byte
  switch(levelType)
    {
      case 255: break;

      case 105: case 113:
        {
          unsigned long value = (unsigned long)gribGetLongDefault(gribHandle, valueKey, 0);
          unsigned long coordinateCount = (unsigned long)gribGetLongDefault(gribHandle, "numberOfCoordinatesValues", 0);
          if(value >= coordinateCount/2)
            {
              Error("Invalid level coordinate: Level has the hybrid coordinate index %lu, but only %lu coordinate pairs are present.", value, coordinateCount/2);
              return CDI_EUFSTRUCT;
            }
          int status;
          //XXX: I'm not 100% sure about how the coordinate pairs are stored in the file.
          //     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.
446
447
          if((status = grib_get_double_element(gribHandle, "pv", (int)value*2    , outValue1))) return status;
          if((status = grib_get_double_element(gribHandle, "pv", (int)value*2 + 1, outValue2))) return status;
448
449
450
451
452
453
454
455
456
457
458
459
460
461
          break;
        }

      default:
        {
          long power = gribGetLongDefault(gribHandle, powerKey, 0);  //1 byte
          if(power == 255) power = 0;
          long value = gribGetLongDefault(gribHandle, valueKey, 0);   //4 bytes
          *outValue1 = logicalLevelValue2(levelType, value, power);
        }
    }
  return CDI_NOERR;
}

462
int cdiGribIterator_level(CdiIterator *super, int levelSelector, double *outValue1, double *outValue2)
463
{
464
  CdiGribIterator *me = (CdiGribIterator*)super;
465
466
467
468
469
  double trash;
  if(!outValue1) outValue1 = &trash;
  if(!outValue2) outValue2 = &trash;
  *outValue1 = *outValue2 = 0;

470
  if(gribEditionNumber(me->gribHandle) > 1)
471
472
473
    {
      if(levelSelector)
        {
474
          return readLevel2(me->gribHandle, "typeOfFirstFixedSurface", "scaleFactorOfFirstFixedSurface", "scaledValueOfFirstFixedSurface", outValue1, outValue2);
475
476
477
        }
      else
        {
478
          return readLevel2(me->gribHandle, "typeOfSecondFixedSurface", "scaleFactorOfSecondFixedSurface", "scaledValueOfSecondFixedSurface", outValue1, outValue2);
479
480
481
482
        }
    }
  else
    {
483
      long levelType = (uint8_t)gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", -1);    //1 byte
484
485
      if(levelType == 255)
        {}
Thomas Jahns's avatar
Thomas Jahns committed
486
      else if(isGrib1DualLevel((int)levelType))
487
        {
488
          *outValue1 = (double)gribGetLongDefault(me->gribHandle, (levelSelector ? "bottomLevel" : "topLevel"), 0);
489
490
491
        }
      else if(levelType == 100)
        {
492
          *outValue1 = 100 * (double)gribGetLongDefault(me->gribHandle, "level", 0);        //2 bytes
493
494
495
        }
      else
        {
496
          *outValue1 = (double)gribGetLongDefault(me->gribHandle, "level", 0);        //2 bytes
497
498
499
500
501
        }
    }
  return CDI_NOERR;
}

502
int cdiGribIterator_zaxisUuid(CdiIterator *super, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE])
503
{
504
  CdiGribIterator *me = (CdiGribIterator*)super;
505
506
507
508

  if(outVgridNumber)
    {
      long temp;
509
      if(grib_get_long(me->gribHandle, "numberOfVGridUsed", &temp)) return CDI_EINVAL;
510
511
512
513
514
      *outVgridNumber = (int)temp;
    }
  if(outLevelCount)
    {
      long temp;
515
      if(grib_get_long(me->gribHandle, "nlev", &temp)) return CDI_EINVAL;
516
517
518
519
      *outLevelCount = (int)temp;
    }
  if(outUuid)
    {
520
      size_t size = CDI_UUID_SIZE;
521
      if(grib_get_bytes(me->gribHandle, "uuidOfVGrid", outUuid, &size)) return CDI_EINVAL;
522
      if(size != CDI_UUID_SIZE) return CDI_EUFSTRUCT;
523
524
525
526
527
    }

  return CDI_NOERR;
}

528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
int cdiGribIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
{
  CdiGribIterator *me = (CdiGribIterator*)super;
  int trash;
  if(!outTileIndex) outTileIndex = &trash;
  if(!outTileAttribute) outTileAttribute = &trash;

  //Get the values if possible.
  int error = CDI_NOERR;
  long value;
  if(grib_get_long(me->gribHandle, "tileIndex", &value)) error = CDI_EINVAL;
  *outTileIndex = (int)value;
  if(grib_get_long(me->gribHandle, "tileAttribute", &value)) error = CDI_EINVAL;
  *outTileAttribute = (int)value;

  //Ensure defined return values in case of failure.
  if(error) *outTileIndex = *outTileAttribute = -1;
  return error;
}

int cdiGribIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
{
  CdiGribIterator *me = (CdiGribIterator*)super;
  int trash;
  if(!outTileCount) outTileCount = &trash;
  if(!outTileAttributeCount) outTileAttributeCount = &trash;

  //Get the values if possible.
  int error = CDI_NOERR;
  long value;
  if(grib_get_long(me->gribHandle, "numberOfTiles", &value)) error = CDI_EINVAL;
  *outTileCount = (int)value;
  if(grib_get_long(me->gribHandle, "numberOfTileAttributes", &value)) error = CDI_EINVAL;
  *outTileAttributeCount = (int)value;

  //Ensure defined return values in case of failure.
  if(error) *outTileCount = *outTileAttributeCount = 0;
  return error;
}

568
char *cdiGribIterator_copyVariableName(CdiIterator *super)
569
{
570
  CdiGribIterator *me = (CdiGribIterator*)super;
571
  return gribCopyString(me->gribHandle, "shortName");
572
573
}

574
void cdiGribIterator_readField(CdiIterator *super, double *buffer, size_t *nmiss)
575
{
576
  CdiGribIterator *me = (CdiGribIterator*)super;
577

578
  GRIB_CHECK(my_grib_set_double(me->gribHandle, "missingValue", cdiDefaultMissval), 0);
579
580
  gribGetDoubleArray(me->gribHandle, "values", buffer);
  long gridType = gribGetLong(me->gribHandle, "gridDefinitionTemplateNumber");
581
582
  if(nmiss)
    {
583
      *nmiss = (gridType >= 50 && gridType <= 53) ? (size_t)0 : (size_t)gribGetLong(me->gribHandle, "numberOfMissing");        //The condition excludes harmonic data.
584
585
586
    }
}

587
void cdiGribIterator_readFieldF(CdiIterator *super, float *buffer, size_t *nmiss)
588
{
589
  CdiGribIterator *me = (CdiGribIterator*)super;
590

591
  size_t valueCount = gribGetArraySize(me->gribHandle, "values");
592
  double *temp = (double *) Malloc(valueCount*sizeof(*temp));
593
  cdiGribIterator_readField(super, temp, nmiss);
Thomas Jahns's avatar
Thomas Jahns committed
594
  for(size_t i = valueCount; i--; ) buffer[i] = (float)temp[i];
595
  Free(temp);
596
}
Thomas Jahns's avatar
Thomas Jahns committed
597
#endif
598

599
/*
600
601
602
@Function cdiGribIterator_delete
@Title Dispose off a CdiGribIterator instance.

603
@Prototype void cdiGribIterator_delete(CdiGribIterator *me)
604
605
606
607
608
609
@Parameter
    @item me The iterator to delete.

@Description
    Combined destructor and deallocator. Make sure to match every call to cdiGribIterator_clone() with a call to this function.
*/
610
void cdiGribIterator_delete(CdiGribIterator *me)
611
{
Thomas Jahns's avatar
Thomas Jahns committed
612
#ifdef HAVE_LIBGRIB_API
613
  if(me) cdiGribIterator_condestruct(me, NULL, 0);
Thomas Jahns's avatar
Thomas Jahns committed
614
615
616
617
#else
  (void)me;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
#endif
618
619
620
621
622
623
624
}


////////////////////////////////////////////////////////////////////////////////////////////////////
// callthroughs to provide direct access to the grib keys //////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

625
/*
626
627
628
@Function cdiGribIterator_inqEdition
@Title Get the version of the GRIB standard that is used

629
@Prototype int cdiGribIterator_inqEdition(CdiGribIterator *me)
630
631
632
633
634
635
636
637
@Parameter
    @item me The iterator to operate on.

@Result The GRIB version.

@Description
    Returns the version of the file format.
*/
638
int cdiGribIterator_inqEdition(CdiGribIterator *me)
639
{
Thomas Jahns's avatar
Thomas Jahns committed
640
#ifdef HAVE_LIBGRIB_API
641
  return (int)gribEditionNumber(me->gribHandle);
Thomas Jahns's avatar
Thomas Jahns committed
642
643
644
645
#else
  (void)me;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
#endif
646
647
}

648
/*
649
650
651
@Function cdiGribIterator_getLong
@Title Access to grib_get_long()

652
@Prototype int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *result)
653
654
655
656
657
658
659
660
661
@Parameter
    @item me The iterator to operate on.
    @item ... The arguments to the underlying GRIB-API function.

@Result An error code.

@Description
    Callthrough to grib_get_long().
*/
662
int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *result)
663
{
Thomas Jahns's avatar
Thomas Jahns committed
664
#ifdef HAVE_LIBGRIB_API
665
  return grib_get_long(me->gribHandle, key, result);
Thomas Jahns's avatar
Thomas Jahns committed
666
667
668
669
670
671
#else
  (void)me;
  (void)key;
  (void)result;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
#endif
672
673
}

674
/*
675
676
677
@Function cdiGribIterator_getLength
@Title Access to grib_get_length()

678
@Prototype int cdiGribIterator_getLength(CdiGribIterator *me, const char *key, size_t *result)
679
680
681
682
683
684
685
686
687
@Parameter
    @item me The iterator to operate on.
    @item ... The arguments to the underlying GRIB-API function.

@Result An error code.

@Description
    Callthrough to grib_get_length().
*/
688
int cdiGribIterator_getLength(CdiGribIterator *me, const char *key, size_t *result)
689
{
690
#ifdef HAVE_GRIB_GET_LENGTH
691
  return grib_get_length(me->gribHandle, key, result);
Thomas Jahns's avatar
Thomas Jahns committed
692
693
694
695
696
#elif defined(HAVE_LIBGRIB_API)
  (void)me;
  (void)key;
  (void)result;
  Error("grib_get_length() is not available, so cdiGribIterator_getLength() can't be used");
697
  return -1;
Thomas Jahns's avatar
Thomas Jahns committed
698
699
700
701
702
#else
  (void)me;
  (void)key;
  (void)result;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
703
#endif
704
705
}

706
/*
707
708
709
@Function cdiGribIterator_getString
@Title Access to grib_get_string()

710
@Prototype int cdiGribIterator_getString(CdiGribIterator *me, const char *key, char *result, size_t *length)
711
712
713
714
715
716
717
718
719
@Parameter
    @item me The iterator to operate on.
    @item ... The arguments to the underlying GRIB-API function.

@Result An error code.

@Description
    Callthrough to grib_get_string().
*/
720
int cdiGribIterator_getString(CdiGribIterator *me, const char *key, char *result, size_t *length)
721
{
Thomas Jahns's avatar
Thomas Jahns committed
722
#ifdef HAVE_LIBGRIB_API
723
  return grib_get_string(me->gribHandle, key, result, length);
Thomas Jahns's avatar
Thomas Jahns committed
724
725
726
727
728
729
730
#else
  (void)me;
  (void)key;
  (void)result;
  (void)length;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
#endif
731
732
}

733
/*
734
735
736
@Function cdiGribIterator_inqLongValue
@Title Get the value of a GRIB-API key as a long

737
@Prototype long cdiGribIterator_inqLongValue(CdiGribIterator *me, const char *key)
738
739
740
741
742
743
744
745
746
747
@Parameter
    @item me The iterator to operate on.
    @item key The GRIB-API key to retrieve.

@Result The value of the key.

@Description
    Use this to fetch a grib value if you are certain that the given key must be present.
    This will abort the process if the key cannot be retrieved.
*/
748
long cdiGribIterator_inqLongValue(CdiGribIterator *me, const char *key)
749
{
Thomas Jahns's avatar
Thomas Jahns committed
750
#ifdef HAVE_LIBGRIB_API
751
  return gribGetLong(me->gribHandle, key);
Thomas Jahns's avatar
Thomas Jahns committed
752
753
754
755
756
#else
  (void)me;
  (void)key;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
#endif
757
758
}

759
/*
760
761
762
@Function cdiGribIterator_inqLongDefaultValue
@Title Get the value of a GRIB-API key as a long

763
@Prototype long cdiGribIterator_inqLongDefaultValue(CdiGribIterator *me, const char *key, long defaultValue)
764
765
766
767
768
769
770
771
772
773
774
@Parameter
    @item me The iterator to operate on.
    @item key The GRIB-API key to retrieve.
    @item defaultValue The value to return if the key is not present.

@Result The value of the key or the given default value.

@Description
    Use this if you can handle failure to fetch the key by supplying a default value.
    This function cannot fail.
*/
775
long cdiGribIterator_inqLongDefaultValue(CdiGribIterator *me, const char *key, long defaultValue)
776
{
Thomas Jahns's avatar
Thomas Jahns committed
777
#ifdef HAVE_LIBGRIB_API
778
  return gribGetLongDefault(me->gribHandle, key, defaultValue);
Thomas Jahns's avatar
Thomas Jahns committed
779
780
781
782
783
784
#else
  (void)me;
  (void)key;
  (void)defaultValue;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
#endif
785
786
}

787
/*
788
789
790
@Function cdiGribIterator_inqStringValue
@Title Safely retrieve a GRIB-API key with a string value

791
@Prototype char *cdiGribIterator_inqStringValue(CdiGribIterator *me, const char *key)
792
793
794
795
796
797
798
799
800
801
802
@Parameter
    @item me The iterator to operate on.
    @item key The GRIB-API key to retrieve.

@Result A malloc'ed string or NULL.

@Description
    This will first call grib_get_length() to inquire the actual size of the string,
    allocate memory accordingly, call grib_get_string(), and return the pointer to the new string.
    Returns NULL on failure.
*/
803
char *cdiGribIterator_inqStringValue(CdiGribIterator *me, const char *key)
804
{
Thomas Jahns's avatar
Thomas Jahns committed
805
#ifdef HAVE_LIBGRIB_API
806
  return gribCopyString(me->gribHandle, key);
Thomas Jahns's avatar
Thomas Jahns committed
807
808
809
810
811
#else
  (void)me;
  (void)key;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
#endif
812
813
}

814
/*
815
816
817
@Function cdiGribIterator_getDouble
@Title Access to grib_get_double()

818
@Prototype int cdiGribIterator_getDouble(CdiGribIterator *me, const char *key, double *result)
819
820
821
822
823
824
825
826
827
@Parameter
    @item me The iterator to operate on.
    @item ... The arguments to the underlying GRIB-API function.

@Result An error code.

@Description
    Callthrough to grib_get_double().
*/
828
int cdiGribIterator_getDouble(CdiGribIterator *me, const char *key, double *result)
829
{
Thomas Jahns's avatar
Thomas Jahns committed
830
#ifdef HAVE_LIBGRIB_API
831
  return grib_get_double(me->gribHandle, key, result);
Thomas Jahns's avatar
Thomas Jahns committed
832
833
834
835
836
837
#else
  (void)me;
  (void)key;
  (void)result;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
#endif
838
839
}

840
/*
841
842
843
@Function cdiGribIterator_getSize
@Title Access to grib_get_size()

844
@Prototype int cdiGribIterator_getSize(CdiGribIterator *me, const char *key, size_t *result)
845
846
847
848
849
850
851
852
853
@Parameter
    @item me The iterator to operate on.
    @item ... The arguments to the underlying GRIB-API function.

@Result An error code.

@Description
    Callthrough to grib_get_size().
*/
854
int cdiGribIterator_getSize(CdiGribIterator *me, const char *key, size_t *result)
855
{
Thomas Jahns's avatar
Thomas Jahns committed
856
#ifdef HAVE_LIBGRIB_API
857
  return grib_get_size(me->gribHandle, key, result);
Thomas Jahns's avatar
Thomas Jahns committed
858
859
860
861
862
863
#else
  (void)me;
  (void)key;
  (void)result;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
#endif
864
865
}

866
/*
867
868
869
@Function cdiGribIterator_getLongArray
@Title Access to grib_get_long_array()

870
@Prototype int cdiGribIterator_getLongArray(CdiGribIterator *me, const char *key, long *result, size_t *size)
871
872
873
874
875
876
877
878
879
@Parameter
    @item me The iterator to operate on.
    @item ... The arguments to the underlying GRIB-API function.

@Result An error code.

@Description
    Callthrough to grib_get_long_array().
*/
880
int cdiGribIterator_getLongArray(CdiGribIterator *me, const char *key, long *result, size_t *size)
881
{
Thomas Jahns's avatar
Thomas Jahns committed
882
#ifdef HAVE_LIBGRIB_API
883
  return grib_get_long_array(me->gribHandle, key, result, size);
Thomas Jahns's avatar
Thomas Jahns committed
884
885
886
887
888
889
890
#else
  (void)me;
  (void)key;
  (void)result;
  (void)size;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
#endif
891
892
}

893
/*
894
895
896
@Function cdiGribIterator_getDoubleArray
@Title Access to grib_get_double_array()

897
@Prototype int cdiGribIterator_getDoubleArray(CdiGribIterator *me, const char *key, double *result, size_t *size)
898
899
900
901
902
903
904
905
906
@Parameter
    @item me The iterator to operate on.
    @item ... The arguments to the underlying GRIB-API function.

@Result An error code.

@Description
    Callthrough to grib_get_double_array().
*/
907
int cdiGribIterator_getDoubleArray(CdiGribIterator *me, const char *key, double *result, size_t *size)
908
{
Thomas Jahns's avatar
Thomas Jahns committed
909
#ifdef HAVE_LIBGRIB_API
910
  return grib_get_double_array(me->gribHandle, key, result, size);
Thomas Jahns's avatar
Thomas Jahns committed
911
912
913
914
915
916
917
#else
  (void)me;
  (void)key;
  (void)result;
  (void)size;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
#endif
918
919
}

920
/*
921
922
923
@Function cdiGribIterator_inqDoubleValue
@Title Get the value of a GRIB-API key as a double

924
@Prototype double cdiGribIterator_inqDoubleValue(CdiGribIterator *me, const char *key)
925
926
927
928
929
930
931
932
933
934
@Parameter
    @item me The iterator to operate on.
    @item key The GRIB-API key to retrieve.

@Result The value of the key.

@Description
    Use this to fetch a grib value if you are certain that the given key must be present.
    This will abort the process if the key cannot be retrieved.
*/
935
double cdiGribIterator_inqDoubleValue(CdiGribIterator *me, const char *key)
936
{
Thomas Jahns's avatar
Thomas Jahns committed
937
#ifdef HAVE_LIBGRIB_API
938
  return gribGetDouble(me->gribHandle, key);
Thomas Jahns's avatar
Thomas Jahns committed
939
940
941
942
943
#else
  (void)me;
  (void)key;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
#endif
944
945
}

946
/*
947
948
949
@Function cdiGribIterator_inqDoubleDefaultValue
@Title Get the value of a GRIB-API key as a double

950
@Prototype double cdiGribIterator_inqDoubleDefaultValue(CdiGribIterator *me, const char *key, double defaultValue)
951
952
953
954
955
956
957
958
959
960
961
@Parameter
    @item me The iterator to operate on.
    @item key The GRIB-API key to retrieve.
    @item defaultValue The value to return if the key is not present.

@Result The value of the key or the given default value.

@Description
    Use this if you can handle failure to fetch the key by supplying a default value.
    This function cannot fail.
*/
962
double cdiGribIterator_inqDoubleDefaultValue(CdiGribIterator *me, const char *key, double defaultValue)
963
{
Thomas Jahns's avatar
Thomas Jahns committed
964
#ifdef HAVE_LIBGRIB_API
965
  return gribGetDoubleDefault(me->gribHandle, key, defaultValue);
Thomas Jahns's avatar
Thomas Jahns committed
966
967
968
969
970
#else
  (void)me;
  (void)key;
  (void)defaultValue;
  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
971
#endif
Thomas Jahns's avatar
Thomas Jahns committed
972
}
973
974
975
976
977
978
979
980
981
982

/*
 * Local Variables:
 * c-file-style: "Java"
 * c-basic-offset: 2
 * indent-tabs-mode: nil
 * show-trailing-whitespace: t
 * require-trailing-newline: t
 * End:
 */