eccodes/src/grib_index.cc

2057 lines
57 KiB
C++

/*
* (C) Copyright 2005- ECMWF.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
*
* In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
* virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
*/
#include "grib_api_internal.h"
#include <map>
#include <string>
#define UNDEF_LONG -99999
#define UNDEF_DOUBLE -99999
#define NULL_MARKER 0
#define NOT_NULL_MARKER 255
#define GRIB_KEY_UNDEF "undef"
/* #if GRIB_PTHREADS */
// static pthread_once_t once = PTHREAD_ONCE_INIT;
// static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
// static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
// static void init() {
// pthread_mutexattr_t attr;
// pthread_mutexattr_init(&attr);
// pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
// pthread_mutex_init(&mutex1,&attr);
// pthread_mutex_init(&mutex2,&attr);
// pthread_mutexattr_destroy(&attr);
// }
// /* #elif GRIB_OMP_THREADS */
// static int once = 0;
// static omp_nest_lock_t mutex1;
// static omp_nest_lock_t mutex2;
// static void init()
// {
// GRIB_OMP_CRITICAL(lock_grib_index_c)
// {
// if (once == 0)
// {
// omp_init_nest_lock(&mutex1);
// omp_init_nest_lock(&mutex2);
// once = 1;
// }
// }
// }
static const char* mars_keys =
"mars.date,mars.time,mars.expver,mars.stream,mars.class,mars.type,"
"mars.step,mars.param,mars.levtype,mars.levelist,mars.number,mars.iteration,"
"mars.domain,mars.fcmonth,mars.fcperiod,mars.hdate,mars.method,"
"mars.model,mars.origin,mars.quantile,mars.range,mars.refdate,mars.direction,mars.frequency";
/* See GRIB-32: start off ID with -1 as it is incremented before being used */
static int grib_filesid = -1;
static int index_count;
static long values_count = 0;
static int codes_index_add_file_internal(grib_index* index, const char* filename, int message_type);
static char* get_key(char** keys, int* type)
{
char* key = NULL;
char* p = NULL;
if (keys == NULL || *keys == 0)
return NULL;
*type = GRIB_TYPE_UNDEFINED;
p = *keys;
while (*p == ' ')
p++;
while (*p != 0 && *p != ':' && *p != ',')
p++;
if (*p == ':') {
*type = grib_type_to_int(*(p + 1));
*p = 0;
p++;
while (*p != 0 && *p != ',') {
*(p++) = 0;
}
}
else
*type = GRIB_TYPE_UNDEFINED;
if (*p) {
*p = 0;
p++;
}
key = *keys;
*keys = *p == 0 ? NULL : p;
return key;
}
static int compare_long(const void* a, const void* b)
{
long* arg1 = (long*)a;
long* arg2 = (long*)b;
if (*arg1 == *arg2)
return 0;
return *arg1 < *arg2 ? -1 : 1;
}
static int compare_double(const void* a, const void* b)
{
double* arg1 = (double*)a;
double* arg2 = (double*)b;
if (*arg1 == *arg2)
return 0;
return *arg1 < *arg2 ? -1 : 1;
}
static int compare_string(const void* a, const void* b)
{
char* arg1 = *(char* const*)a;
char* arg2 = *(char* const*)b;
while (*arg1 != 0 && *arg2 != 0 && *arg1 == *arg2) {
arg1++;
arg2++;
}
if (*arg1 == *arg2)
return 0;
return *arg1 < *arg2 ? -1 : 1;
}
static int grib_index_keys_compress(grib_context* c, grib_index* index, int* compress)
{
grib_index_key* keys = index->keys->next;
grib_index_key* prev = index->keys;
int level = 0;
if (!keys)
return 0;
level = 1;
while (keys) {
if (keys->values_count == 1) {
prev->next = keys->next;
grib_context_free(c, keys->name);
grib_context_free(c, keys);
keys = prev->next;
compress[level] = 1;
level++;
}
else {
prev = keys;
keys = keys->next;
compress[level] = 0;
level++;
}
}
if (index->keys->values_count == 1) {
keys = index->keys;
index->keys = index->keys->next;
grib_context_free(c, keys->name);
grib_context_free(c, keys);
compress[0] = 1;
}
else
compress[0] = 0;
return 0;
}
static int grib_index_fields_compress(grib_context* c,
grib_field_tree* fields, grib_field_tree* prev, int level, int* compress)
{
if (!fields)
return 0;
if (!prev) {
if (fields->next)
grib_index_fields_compress(c, fields->next, 0, level, compress);
level++;
return grib_index_fields_compress(c, fields->next_level, fields, level, compress);
}
if (compress[level]) {
if (!fields->next_level)
prev->field = fields->field;
prev->next_level = fields->next_level;
grib_context_free(c, fields->value);
grib_context_free(c, fields);
level++;
grib_index_fields_compress(c, prev->next_level, prev, level, compress);
}
else {
grib_field_tree* next;
next = fields->next;
level++;
while (next) {
grib_index_fields_compress(c, next->next_level, next, level, compress);
next = next->next;
}
grib_index_fields_compress(c, fields->next_level, fields, level, compress);
}
return 0;
}
int grib_index_compress(grib_index* index)
{
int err = 0;
grib_context* c = index->context;
int compress[200] = {0,};
if (!index->keys->next)
return 0;
err = grib_index_keys_compress(c, index, compress);
if (err) return err;
err = grib_index_fields_compress(c, index->fields, 0, 0, compress);
if (err) return err;
if (!index->fields->next) {
grib_field_tree* next_level = index->fields->next_level;
grib_context_free(c, index->fields->value);
grib_context_free(c, index->fields);
index->fields = next_level;
}
return 0;
}
static grib_index_key* grib_index_new_key(grib_context* c, grib_index_key* keys,
const char* key, int type, int* err)
{
grib_index_key *next = NULL, *current = NULL;
grib_string_list* values = NULL;
next = (grib_index_key*)grib_context_malloc_clear(c, sizeof(grib_index_key));
if (!next) {
grib_context_log(c, GRIB_LOG_ERROR, "Unable to allocate %zu bytes", sizeof(grib_index_key));
*err = GRIB_OUT_OF_MEMORY;
return NULL;
}
values = (grib_string_list*)grib_context_malloc_clear(c, sizeof(grib_string_list));
if (!values) {
grib_context_log(c, GRIB_LOG_ERROR, "Unable to allocate %zu bytes", sizeof(grib_string_list));
*err = GRIB_OUT_OF_MEMORY;
return NULL;
}
next->values = values;
if (!keys) {
keys = next;
current = keys;
}
else {
current = keys;
while (current->next)
current = current->next;
current->next = next;
current = current->next;
}
current->type = type;
current->name = grib_context_strdup(c, key);
return keys;
}
static int grib_read_uchar(FILE* fh, unsigned char* val)
{
if (fread(val, sizeof(unsigned char), 1, fh) < 1) {
if (feof(fh))
return GRIB_END_OF_FILE;
else
return GRIB_IO_PROBLEM;
}
return GRIB_SUCCESS;
}
static int grib_read_short(FILE* fh, short* val)
{
if (fread(val, sizeof(short), 1, fh) < 1) {
if (feof(fh))
return GRIB_END_OF_FILE;
else
return GRIB_IO_PROBLEM;
}
return GRIB_SUCCESS;
}
// static int grib_read_long(FILE* fh, long* val)
// {
// if (fread(val, sizeof(long), 1, fh) < 1) {
// if (feof(fh))
// return GRIB_END_OF_FILE;
// else
// return GRIB_IO_PROBLEM;
// }
// return GRIB_SUCCESS;
// }
static int grib_read_unsigned_long(FILE* fh, unsigned long* val)
{
if (fread(val, sizeof(long), 1, fh) < 1) {
if (feof(fh))
return GRIB_END_OF_FILE;
else
return GRIB_IO_PROBLEM;
}
return GRIB_SUCCESS;
}
static int grib_write_uchar(FILE* fh, unsigned char val)
{
if (fwrite(&val, sizeof(unsigned char), 1, fh) < 1)
return GRIB_IO_PROBLEM;
return GRIB_SUCCESS;
}
static int grib_write_short(FILE* fh, short val)
{
if (fwrite(&val, sizeof(short), 1, fh) < 1)
return GRIB_IO_PROBLEM;
return GRIB_SUCCESS;
}
// static int grib_write_long(FILE* fh, long val)
// {
// if (fwrite(&val, sizeof(long), 1, fh) < 1)
// return GRIB_IO_PROBLEM;
// return GRIB_SUCCESS;
// }
static int grib_write_unsigned_long(FILE* fh, unsigned long val)
{
if (fwrite(&val, sizeof(long), 1, fh) < 1)
return GRIB_IO_PROBLEM;
return GRIB_SUCCESS;
}
static int grib_write_string(FILE* fh, const char* s)
{
size_t len = 0;
if (s == NULL)
return GRIB_IO_PROBLEM;
len = strlen(s);
grib_write_uchar(fh, (unsigned char)len);
if (fwrite(s, 1, len, fh) < len)
return GRIB_IO_PROBLEM;
return GRIB_SUCCESS;
}
static int grib_write_identifier(FILE* fh, const char* ID)
{
return grib_write_string(fh, ID);
}
static int grib_write_null_marker(FILE* fh)
{
return grib_write_uchar(fh, NULL_MARKER);
}
static int grib_write_not_null_marker(FILE* fh)
{
return grib_write_uchar(fh, NOT_NULL_MARKER);
}
static char* grib_read_string(grib_context* c, FILE* fh, int* err)
{
unsigned char len = 0;
char* s = NULL;
*err = grib_read_uchar(fh, &len);
if (*err)
return NULL;
s = (char*)grib_context_malloc_clear(c, len + 1);
if (fread(s, len, 1, fh) < 1) {
if (feof(fh))
*err = GRIB_END_OF_FILE;
else
*err = GRIB_IO_PROBLEM;
return NULL;
}
s[len] = 0;
return s;
}
static int grib_write_field(FILE* fh, grib_field* field)
{
int err;
if (!field)
return grib_write_null_marker(fh);
err = grib_write_not_null_marker(fh);
if (err)
return err;
err = grib_write_short(fh, field->file->id);
if (err)
return err;
err = grib_write_unsigned_long(fh, field->offset);
if (err)
return err;
err = grib_write_unsigned_long(fh, field->length);
if (err)
return err;
err = grib_write_field(fh, field->next);
if (err)
return err;
return GRIB_SUCCESS;
}
static grib_field* grib_read_field(grib_context* c, FILE* fh, grib_file** files, int* err)
{
grib_field* field = NULL;
short file_id;
unsigned char marker = 0;
unsigned long offset = 0;
unsigned long length = 0;
*err = grib_read_uchar(fh, &marker);
if (marker == NULL_MARKER)
return NULL;
if (marker != NOT_NULL_MARKER) {
*err = GRIB_CORRUPTED_INDEX;
return NULL;
}
index_count++;
field = (grib_field*)grib_context_malloc(c, sizeof(grib_field));
*err = grib_read_short(fh, &file_id);
if (*err)
return NULL;
field->file = files[file_id];
*err = grib_read_unsigned_long(fh, &offset);
field->offset = offset;
if (*err)
return NULL;
*err = grib_read_unsigned_long(fh, &length);
field->length = length;
if (*err)
return NULL;
field->next = grib_read_field(c, fh, files, err);
return field;
}
static int grib_write_field_tree(FILE* fh, grib_field_tree* tree)
{
int err = 0;
if (!tree)
return grib_write_null_marker(fh);
err = grib_write_not_null_marker(fh);
if (err)
return err;
err = grib_write_field(fh, tree->field);
if (err)
return err;
err = grib_write_string(fh, tree->value);
if (err)
return err;
err = grib_write_field_tree(fh, tree->next_level);
if (err)
return err;
err = grib_write_field_tree(fh, tree->next);
if (err)
return err;
return GRIB_SUCCESS;
}
grib_field_tree* grib_read_field_tree(grib_context* c, FILE* fh, grib_file** files, int* err)
{
grib_field_tree* tree = NULL;
unsigned char marker = 0;
*err = grib_read_uchar(fh, &marker);
if (marker == NULL_MARKER)
return NULL;
if (marker != NOT_NULL_MARKER) {
*err = GRIB_CORRUPTED_INDEX;
return NULL;
}
tree = (grib_field_tree*)grib_context_malloc(c, sizeof(grib_field_tree));
tree->field = grib_read_field(c, fh, files, err);
if (*err)
return NULL;
tree->value = grib_read_string(c, fh, err);
if (*err)
return NULL;
tree->next_level = grib_read_field_tree(c, fh, files, err);
if (*err)
return NULL;
tree->next = grib_read_field_tree(c, fh, files, err);
if (*err)
return NULL;
return tree;
}
grib_index* grib_index_new(grib_context* c, const char* key, int* err)
{
grib_index* index;
grib_index_key* keys = NULL;
char* q;
int type;
char* p;
if (!strcmp(key, "mars"))
return grib_index_new(c, mars_keys, err);
p = grib_context_strdup(c, key);
q = p;
*err = 0;
if (!c)
c = grib_context_get_default();
index = (grib_index*)grib_context_malloc_clear(c, sizeof(grib_index));
if (!index) {
grib_context_log(c, GRIB_LOG_ERROR, "Unable to create index");
*err = GRIB_OUT_OF_MEMORY;
return NULL;
}
index->context = c;
index->product_kind = PRODUCT_GRIB;
index->unpack_bufr = 0;
while ((key = get_key(&p, &type)) != NULL) {
keys = grib_index_new_key(c, keys, key, type, err);
if (*err)
return NULL;
}
index->keys = keys;
index->fields = (grib_field_tree*)grib_context_malloc_clear(c,
sizeof(grib_field_tree));
if (!index->fields) {
*err = GRIB_OUT_OF_MEMORY;
return NULL;
}
grib_context_free(c, q);
return index;
}
static void grib_index_values_delete(grib_context* c, grib_string_list* values)
{
if (!values)
return;
grib_index_values_delete(c, values->next);
grib_context_free(c, values->value);
grib_context_free(c, values);
return;
}
static void grib_index_key_delete(grib_context* c, grib_index_key* keys)
{
if (!keys)
return;
grib_index_key_delete(c, keys->next);
grib_index_values_delete(c, keys->values);
grib_index_values_delete(c, keys->current);
grib_context_free(c, keys->name);
grib_context_free(c, keys);
}
static grib_string_list* grib_read_key_values(grib_context* c, FILE* fh, int* err)
{
grib_string_list* values;
unsigned char marker = 0;
*err = grib_read_uchar(fh, &marker);
if (marker == NULL_MARKER)
return NULL;
if (marker != NOT_NULL_MARKER) {
*err = GRIB_CORRUPTED_INDEX;
return NULL;
}
values_count++;
values = (grib_string_list*)grib_context_malloc_clear(c, sizeof(grib_string_list));
values->value = grib_read_string(c, fh, err);
if (*err)
return NULL;
values->next = grib_read_key_values(c, fh, err);
if (*err)
return NULL;
return values;
}
static int grib_write_key_values(FILE* fh, grib_string_list* values)
{
int err = 0;
if (!values)
return grib_write_null_marker(fh);
err = grib_write_not_null_marker(fh);
if (err)
return err;
err = grib_write_string(fh, values->value);
if (err)
return err;
err = grib_write_key_values(fh, values->next);
if (err)
return err;
return GRIB_SUCCESS;
}
static grib_index_key* grib_read_index_keys(grib_context* c, FILE* fh, int* err)
{
grib_index_key* keys = NULL;
unsigned char marker = 0;
unsigned char type = 0;
if (!c)
c = grib_context_get_default();
*err = grib_read_uchar(fh, &marker);
if (marker == NULL_MARKER)
return NULL;
if (marker != NOT_NULL_MARKER) {
*err = GRIB_CORRUPTED_INDEX;
return NULL;
}
keys = (grib_index_key*)grib_context_malloc_clear(c, sizeof(grib_index_key));
keys->name = grib_read_string(c, fh, err);
if (*err)
return NULL;
*err = grib_read_uchar(fh, &type);
keys->type = type;
if (*err)
return NULL;
values_count = 0;
keys->values = grib_read_key_values(c, fh, err);
if (*err)
return NULL;
keys->values_count = values_count;
keys->next = grib_read_index_keys(c, fh, err);
if (*err)
return NULL;
return keys;
}
static int grib_write_index_keys(FILE* fh, grib_index_key* keys)
{
int err = 0;
if (!keys)
return grib_write_null_marker(fh);
err = grib_write_not_null_marker(fh);
if (err)
return err;
err = grib_write_string(fh, keys->name);
if (err)
return err;
err = grib_write_uchar(fh, (unsigned char)keys->type);
if (err)
return err;
err = grib_write_key_values(fh, keys->values);
if (err)
return err;
err = grib_write_index_keys(fh, keys->next);
if (err)
return err;
return GRIB_SUCCESS;
}
static void grib_field_delete(grib_context* c, grib_field* field)
{
int err = 0;
if (!field)
return;
grib_field_delete(c, field->next);
if (field->file) {
grib_file_close(field->file->name, 0, &err);
field->file = NULL;
}
grib_context_free(c, field);
}
static void grib_field_tree_delete(grib_context* c, grib_field_tree* tree)
{
if (!tree)
return;
grib_field_delete(c, tree->field);
grib_context_free(c, tree->value);
grib_field_tree_delete(c, tree->next_level);
grib_field_tree_delete(c, tree->next);
grib_context_free(c, tree);
}
static void grib_field_list_delete(grib_context* c, grib_field_list* field_list)
{
grib_field_list* p = field_list;
if (!field_list)
return;
while (p) {
grib_field_list* q = p;
p = p->next;
grib_context_free(c, q);
}
}
void grib_index_delete(grib_index* index)
{
grib_file* file = index->files;
grib_index_key_delete(index->context, index->keys);
grib_field_tree_delete(index->context, index->fields);
grib_field_list_delete(index->context, index->fieldset);
while (file) {
grib_file* f = file;
file = file->next;
grib_file_delete(f);
}
grib_context_free(index->context, index);
}
static int grib_write_files(FILE* fh, grib_file* files)
{
int err;
if (!files)
return grib_write_null_marker(fh);
err = grib_write_not_null_marker(fh);
if (err)
return err;
err = grib_write_string(fh, files->name);
if (err)
return err;
err = grib_write_short(fh, (short)files->id);
if (err)
return err;
return grib_write_files(fh, files->next);
}
static grib_file* grib_read_files(grib_context* c, FILE* fh, int* err)
{
unsigned char marker = 0;
short id = 0;
grib_file* file;
*err = grib_read_uchar(fh, &marker);
if (marker == NULL_MARKER)
return NULL;
if (marker != NOT_NULL_MARKER) {
*err = GRIB_CORRUPTED_INDEX;
return NULL;
}
file = (grib_file*)grib_context_malloc(c, sizeof(grib_file));
file->name = grib_read_string(c, fh, err);
if (*err)
return NULL;
*err = grib_read_short(fh, &id);
file->id = id;
if (*err)
return NULL;
file->next = grib_read_files(c, fh, err);
if (*err)
return NULL;
return file;
}
int grib_index_write(grib_index* index, const char* filename)
{
int err = 0;
FILE* fh;
grib_file* files;
const char* identifier = NULL;
fh = fopen(filename, "w");
if (!fh) {
grib_context_log(index->context, (GRIB_LOG_ERROR) | (GRIB_LOG_PERROR),
"Unable to write in file %s", filename);
perror(filename);
return GRIB_IO_PROBLEM;
}
if (index->product_kind == PRODUCT_GRIB) identifier = "GRBIDX1";
if (index->product_kind == PRODUCT_BUFR) identifier = "BFRIDX1";
ECCODES_ASSERT(identifier);
err = grib_write_identifier(fh, identifier);
if (err) {
grib_context_log(index->context, (GRIB_LOG_ERROR) | (GRIB_LOG_PERROR),
"Unable to write in file %s", filename);
perror(filename);
return err;
}
if (!index)
return grib_write_null_marker(fh);
err = grib_write_not_null_marker(fh);
if (err)
return err;
/* See GRIB-32: Do not use the file pool */
/* files=grib_file_pool_get_files(); */
files = index->files;
err = grib_write_files(fh, files);
if (err) {
grib_context_log(index->context, (GRIB_LOG_ERROR) | (GRIB_LOG_PERROR),
"Unable to write in file %s", filename);
perror(filename);
return err;
}
err = grib_write_index_keys(fh, index->keys);
if (err) {
grib_context_log(index->context, (GRIB_LOG_ERROR) | (GRIB_LOG_PERROR),
"Unable to write in file %s", filename);
perror(filename);
return err;
}
err = grib_write_field_tree(fh, index->fields);
if (err) {
grib_context_log(index->context, (GRIB_LOG_ERROR) | (GRIB_LOG_PERROR),
"Unable to write in file %s", filename);
perror(filename);
return err;
}
if (fclose(fh) != 0) {
grib_context_log(index->context, (GRIB_LOG_ERROR) | (GRIB_LOG_PERROR),
"Unable to write in file %s", filename);
perror(filename);
return GRIB_IO_PROBLEM;
}
return err;
}
grib_index* grib_index_read(grib_context* c, const char* filename, int* err)
{
grib_file *file, *f;
grib_file** files;
grib_index* index = NULL;
unsigned char marker = 0;
char* identifier = NULL;
int max = 0;
FILE* fh = NULL;
ProductKind product_kind = PRODUCT_GRIB;
if (!c)
c = grib_context_get_default();
fh = fopen(filename, "r");
if (!fh) {
grib_context_log(c, (GRIB_LOG_ERROR) | (GRIB_LOG_PERROR),
"Unable to read file %s", filename);
perror(filename);
*err = GRIB_IO_PROBLEM;
return NULL;
}
identifier = grib_read_string(c, fh, err);
if (!identifier) {
fclose(fh);
return NULL;
}
if (strcmp(identifier, "BFRIDX1")==0) product_kind = PRODUCT_BUFR;
grib_context_free(c, identifier);
*err = grib_read_uchar(fh, &marker);
if (marker == NULL_MARKER) {
fclose(fh);
return NULL;
}
if (marker != NOT_NULL_MARKER) {
*err = GRIB_CORRUPTED_INDEX;
fclose(fh);
return NULL;
}
file = grib_read_files(c, fh, err);
if (*err)
return NULL;
f = file;
while (f) {
if (max < f->id)
max = f->id;
f = f->next;
}
files = (grib_file**)grib_context_malloc_clear(c, sizeof(grib_file) * (max + 1));
f = file;
while (f) {
grib_file_open(f->name, "r", err);
if (*err)
return NULL;
files[f->id] = grib_get_file(f->name, err); /* fetch from pool */
f = f->next;
}
while (file) {
f = file;
file = file->next;
grib_context_free(c, f->name);
grib_context_free(c, f);
}
index = (grib_index*)grib_context_malloc_clear(c, sizeof(grib_index));
index->context = c;
index->product_kind = product_kind;
index->keys = grib_read_index_keys(c, fh, err);
if (*err)
return NULL;
index_count = 0;
index->fields = grib_read_field_tree(c, fh, files, err);
if (*err)
return NULL;
index->count = index_count;
fclose(fh);
grib_context_free(c, files);
return index;
}
int grib_index_search_same(grib_index* index, grib_handle* h)
{
int err = 0;
char buf[STRING_VALUE_LEN] = {0,};
size_t buflen = STRING_VALUE_LEN;
grib_index_key* keys;
long lval = 0;
double dval = 0.0;
grib_context* c = NULL;
if (!index)
return GRIB_NULL_INDEX;
c = index->context;
keys = index->keys;
while (keys) {
if (keys->type == GRIB_TYPE_UNDEFINED) {
err = grib_get_native_type(h, keys->name, &(keys->type));
if (err)
keys->type = GRIB_TYPE_STRING;
}
buflen = STRING_VALUE_LEN;
switch (keys->type) {
case GRIB_TYPE_STRING:
err = grib_get_string(h, keys->name, buf, &buflen);
if (err == GRIB_NOT_FOUND)
snprintf(buf, sizeof(buf), GRIB_KEY_UNDEF);
break;
case GRIB_TYPE_LONG:
err = grib_get_long(h, keys->name, &lval);
if (err == GRIB_NOT_FOUND)
snprintf(buf, sizeof(buf), GRIB_KEY_UNDEF);
else
snprintf(buf, sizeof(buf), "%ld", lval);
break;
case GRIB_TYPE_DOUBLE:
err = grib_get_double(h, keys->name, &dval);
if (err == GRIB_NOT_FOUND)
snprintf(buf, sizeof(buf), GRIB_KEY_UNDEF);
else
snprintf(buf, sizeof(buf), "%g", dval);
break;
default:
err = GRIB_WRONG_TYPE;
return err;
}
if (err && err != GRIB_NOT_FOUND) {
grib_context_log(c, GRIB_LOG_ERROR,
"Unable to create index. \"%s\": %s",
keys->name, grib_get_error_message(err));
return err;
}
snprintf(keys->value, sizeof(buf), "%s", buf);
keys = keys->next;
}
grib_index_rewind(index);
return 0;
}
int grib_index_add_file(grib_index* index, const char* filename)
{
int message_type = 0;
if (index->product_kind == PRODUCT_GRIB) message_type = CODES_GRIB;
else if (index->product_kind == PRODUCT_BUFR) message_type = CODES_BUFR;
else return GRIB_INVALID_ARGUMENT;
return codes_index_add_file_internal(index, filename, message_type);
}
static grib_handle* new_message_from_file(int message_type, grib_context* c, FILE* f, int* error)
{
if (message_type == CODES_GRIB)
return grib_new_from_file(c, f, 0, error); /* headers_only=0 */
if (message_type == CODES_BUFR)
return bufr_new_from_file(c, f, error);
ECCODES_ASSERT(!"new_message_from_file: invalid message type");
return NULL;
}
#define MAX_NUM_KEYS 40
static int codes_index_add_file_internal(grib_index* index, const char* filename, int message_type)
{
double dval;
size_t svallen;
size_t message_count = 0;
long length, lval;
char buf[1024] = {0,};
int err = 0;
grib_file* indfile;
grib_file* newfile;
grib_index_key* index_key = NULL;
grib_handle* h = NULL;
grib_field* field;
grib_field_tree* field_tree;
grib_file* file = NULL;
grib_context* c;
bool warn_about_duplicates = true;
if (!index)
return GRIB_NULL_INDEX;
c = index->context;
file = grib_file_open(filename, "r", &err);
if (!file || !file->handle)
return err;
if (!index->files) {
grib_filesid++;
newfile = (grib_file*)grib_context_malloc_clear(c, sizeof(grib_file));
newfile->id = grib_filesid;
newfile->name = strdup(file->name);
newfile->handle = file->handle;
index->files = newfile;
}
else {
indfile = index->files;
while (indfile) {
if (!strcmp(indfile->name, file->name))
return 0;
indfile = indfile->next;
}
indfile = index->files;
while (indfile->next)
indfile = indfile->next;
grib_filesid++;
newfile = (grib_file*)grib_context_malloc_clear(c, sizeof(grib_file));
newfile->id = grib_filesid;
newfile->name = strdup(file->name);
newfile->handle = file->handle;
indfile->next = newfile;
}
fseeko(file->handle, 0, SEEK_SET);
std::map<off_t, grib_handle*> map_of_offsets;
while ((h = new_message_from_file(message_type, c, file->handle, &err)) != NULL) {
grib_string_list* v = 0;
index_key = index->keys;
field_tree = index->fields;
index_key->value[0] = 0;
message_count++;
{
const char* set_keys_env_var = "ECCODES_INDEX_SET_KEYS";
char* envsetkeys = getenv(set_keys_env_var);
if (envsetkeys) {
grib_values set_values[MAX_NUM_KEYS];
int set_values_count = MAX_NUM_KEYS;
std::string copy_of_env(envsetkeys); //parse_keyval_string changes envsetkeys!
int error = parse_keyval_string(NULL, envsetkeys, 1, GRIB_TYPE_UNDEFINED,
set_values, &set_values_count);
if (!error && set_values_count != 0) {
err = grib_set_values(h, set_values, set_values_count);
if (err) {
grib_context_log(c, GRIB_LOG_ERROR,
"codes_index_add_file: Unable to set %s", copy_of_env.c_str());
return err;
}
} else {
grib_context_log(c, GRIB_LOG_ERROR, "codes_index_add_file: Unable to parse %s (%s)",
set_keys_env_var, grib_get_error_message(error));
return error;
}
}
}
if (index->product_kind == PRODUCT_BUFR && index->unpack_bufr) {
err = grib_set_long(h, "unpack", 1);
if (err) {
grib_context_log(c, GRIB_LOG_ERROR, "Unable to unpack BUFR to create index. \"%s\": %s",
index_key->name, grib_get_error_message(err));
return err;
}
}
while (index_key) {
if (index_key->type == GRIB_TYPE_UNDEFINED) {
err = grib_get_native_type(h, index_key->name, &(index_key->type));
if (err)
index_key->type = GRIB_TYPE_STRING;
}
svallen = 1024;
switch (index_key->type) {
case GRIB_TYPE_STRING:
err = grib_get_string(h, index_key->name, buf, &svallen);
if (err == GRIB_NOT_FOUND)
snprintf(buf, sizeof(buf), GRIB_KEY_UNDEF);
break;
case GRIB_TYPE_LONG:
err = grib_get_long(h, index_key->name, &lval);
if (err == GRIB_NOT_FOUND)
snprintf(buf, sizeof(buf), GRIB_KEY_UNDEF);
else
snprintf(buf, sizeof(buf), "%ld", lval);
break;
case GRIB_TYPE_DOUBLE:
err = grib_get_double(h, index_key->name, &dval);
if (err == GRIB_NOT_FOUND)
snprintf(buf, sizeof(buf), GRIB_KEY_UNDEF);
else
snprintf(buf, sizeof(buf), "%g", dval);
break;
default:
err = GRIB_WRONG_TYPE;
return err;
}
if (err && err != GRIB_NOT_FOUND) {
grib_context_log(c, GRIB_LOG_ERROR, "Unable to create index. key=\"%s\" (message #%lu): %s",
index_key->name, message_count, grib_get_error_message(err));
return err;
}
if (!index_key->values->value) {
index_key->values->value = grib_context_strdup(c, buf);
index_key->values_count++;
}
else {
v = index_key->values;
while (v->next && strcmp(v->value, buf))
v = v->next;
if (strcmp(v->value, buf)) {
index_key->values_count++;
if (v->next)
v = v->next;
v->next = (grib_string_list*)grib_context_malloc_clear(c, sizeof(grib_string_list));
v->next->value = grib_context_strdup(c, buf);
}
}
if (!field_tree->value) {
field_tree->value = grib_context_strdup(c, buf);
}
else {
while (field_tree->next &&
(field_tree->value == NULL ||
strcmp(field_tree->value, buf)))
field_tree = field_tree->next;
if (!field_tree->value || strcmp(field_tree->value, buf)) {
field_tree->next =
(grib_field_tree*)grib_context_malloc_clear(c,
sizeof(grib_field_tree));
field_tree = field_tree->next;
field_tree->value = grib_context_strdup(c, buf);
}
}
if (index_key->next) {
if (!field_tree->next_level) {
field_tree->next_level =
(grib_field_tree*)grib_context_malloc_clear(c, sizeof(grib_field_tree));
}
field_tree = field_tree->next_level;
}
index_key = index_key->next;
}
field = (grib_field*)grib_context_malloc_clear(c, sizeof(grib_field));
field->file = file;
index->count++;
field->offset = h->offset;
if (warn_about_duplicates) {
const bool offset_is_unique = map_of_offsets.insert( std::pair<off_t, grib_handle*>(h->offset, h) ).second;
if (!offset_is_unique) {
fprintf(stderr, "ECCODES WARNING : File '%s': field offset %ld is not unique.\n", filename, (long)h->offset);
long edition = 0;
if (grib_get_long(h, "edition", &edition) == GRIB_SUCCESS && edition == 2) {
fprintf(stderr, "ECCODES WARNING : This can happen if the file contains multi-field GRIB messages.\n");
fprintf(stderr, "ECCODES WARNING : Indexing multi-field messages is not fully supported.\n");
}
warn_about_duplicates = false;
}
}
err = grib_get_long(h, "totalLength", &length);
if (err)
return err;
field->length = length;
if (field_tree->field) {
grib_field* pfield = field_tree->field;
while (pfield->next)
pfield = pfield->next;
pfield->next = field;
}
else
field_tree->field = field;
grib_handle_delete(h);
}/*foreach message*/
grib_file_close(file->name, 0, &err);
if (err)
return err;
index->rewind = 1;
if (message_count == 0) {
grib_context_log(c, GRIB_LOG_ERROR, "File %s contains no messages", filename);
return GRIB_END_OF_FILE;
}
if (c->debug) {
fprintf(stderr, "ECCODES DEBUG %s %s\n", __func__, filename);
grib_index_dump(stderr, index, GRIB_DUMP_FLAG_TYPE);
}
return GRIB_SUCCESS;
}
// int grib_index_add_file(grib_index* index, const char* filename)
// {
// double dval;
// size_t svallen;
// long length,lval;
// char buf[1024]={0,};
// int err=0;
// grib_file* indfile;
// grib_file* newfile;
// grib_index_key* index_key=NULL;
// grib_handle* h=NULL;
// grib_field* field;
// grib_field_tree* field_tree;
// grib_file* file=NULL;
// grib_context* c;
// if (!index) return GRIB_NULL_INDEX;
// c=index->context;
// file=grib_file_open(filename,"r",&err);
// if (!file || !file->handle) return err;
// if (!index->files) {
// grib_filesid++;
// newfile=(grib_file*)grib_context_malloc_clear(c,sizeof(grib_file));
// newfile->id=grib_filesid;
// newfile->name=strdup(file->name);
// newfile->handle = file->handle;
// index->files=newfile;
// } else {
// indfile=index->files;
// while(indfile) {
// if (!strcmp(indfile->name,file->name)) return 0;
// indfile=indfile->next;
// }
// indfile=index->files;
// while(indfile->next) indfile=indfile->next;
// grib_filesid++;
// newfile=(grib_file*)grib_context_malloc_clear(c,sizeof(grib_file));
// newfile->id=grib_filesid;
// newfile->name=strdup(file->name);
// newfile->handle = file->handle;
// indfile->next=newfile;
// }
// fseeko(file->handle,0,SEEK_SET);
// while ((h=grib_handle_new_from_file(c,file->handle,&err))!=NULL) {
// grib_string_list* v=0;
// index_key=index->keys;
// field_tree=index->fields;
// index_key->value[0]=0;
// /* process only GRIB for the moment*/
// svallen=1024;
// grib_get_string(h,"identifier",buf,&svallen);
// if (strcmp(buf,"GRIB")) {
// grib_handle_delete(h);
// return 0;
// }
// while (index_key) {
// if (index_key->type==GRIB_TYPE_UNDEFINED) {
// err=grib_get_native_type(h,index_key->name,&(index_key->type));
// if (err) index_key->type=GRIB_TYPE_STRING;
// }
// svallen=1024;
// switch (index_key->type) {
// case GRIB_TYPE_STRING:
// err=grib_get_string(h,index_key->name,buf,&svallen);
// if (err==GRIB_NOT_FOUND) snprintf(buf,1024,GRIB_KEY_UNDEF);
// break;
// case GRIB_TYPE_LONG:
// err=grib_get_long(h,index_key->name,&lval);
// if (err==GRIB_NOT_FOUND) snprintf(buf,1024,GRIB_KEY_UNDEF);
// else snprintf(buf,1024,"%ld",lval);
// break;
// case GRIB_TYPE_DOUBLE:
// err=grib_get_double(h,index_key->name,&dval);
// if (err==GRIB_NOT_FOUND) snprintf(buf,1024,GRIB_KEY_UNDEF);
// else snprintf(buf,1024,"%g",dval);
// break;
// default :
// err=GRIB_WRONG_TYPE;
// return err;
// }
// if (err && err != GRIB_NOT_FOUND) {
// grib_context_log(c,GRIB_LOG_ERROR,"Unable to create index. \"%s\": %s",index_key->name,grib_get_error_message(err));
// return err;
// }
// if (!index_key->values->value) {
// index_key->values->value=grib_context_strdup(c,buf);
// index_key->values_count++;
// } else {
// v=index_key->values;
// while (v->next && strcmp(v->value,buf)) v=v->next;
// if (strcmp(v->value,buf)) {
// index_key->values_count++;
// if (v->next) v=v->next;
// v->next=(grib_string_list*)grib_context_malloc_clear(c,sizeof(grib_string_list));
// v->next->value=grib_context_strdup(c,buf);
// }
// }
// if (!field_tree->value) {
// field_tree->value=grib_context_strdup(c,buf);
// } else {
// while (field_tree->next &&
// (field_tree->value==NULL ||
// strcmp(field_tree->value,buf)))
// field_tree=field_tree->next;
// if (!field_tree->value || strcmp(field_tree->value,buf)){
// field_tree->next=
// (grib_field_tree*)grib_context_malloc_clear(c,
// sizeof(grib_field_tree));
// field_tree=field_tree->next;
// field_tree->value=grib_context_strdup(c,buf);
// }
// }
// if (index_key->next) {
// if (!field_tree->next_level) {
// field_tree->next_level=
// (grib_field_tree*)grib_context_malloc_clear(c,sizeof(grib_field_tree));
// }
// field_tree=field_tree->next_level;
// }
// index_key=index_key->next;
// }
// field=(grib_field*)grib_context_malloc_clear(c,sizeof(grib_field));
// field->file=file;
// index->count++;
// field->offset=h->offset;
// err=grib_get_long(h,"totalLength",&length);
// if (err) return err;
// field->length=length;
// if (field_tree->field) {
// grib_field* pfield=field_tree->field;
// while (pfield->next) pfield=pfield->next;
// pfield->next=field;
// } else
// field_tree->field=field;
// if (h) grib_handle_delete(h);
// }
// grib_file_close(file->name, 0, &err);
// if (err) return err;
// index->rewind=1;
// return GRIB_SUCCESS;
// }
grib_index* grib_index_new_from_file(grib_context* c, const char* filename, const char* keys, int* err)
{
grib_index* index = NULL;
if (!c)
c = grib_context_get_default();
index = grib_index_new(c, keys, err);
*err = grib_index_add_file(index, filename);
if (*err) {
grib_index_delete(index);
return NULL;
}
return index;
}
int grib_index_get_size(const grib_index* index, const char* key, size_t* size)
{
grib_index_key* k = index->keys;
while (k && strcmp(k->name, key))
k = k->next;
if (!k)
return GRIB_NOT_FOUND;
*size = k->values_count;
return 0;
}
int grib_index_get_string(const grib_index* index, const char* key, char** values, size_t* size)
{
grib_index_key* k = index->keys;
grib_string_list* kv;
int i = 0;
while (k && strcmp(k->name, key))
k = k->next;
if (!k)
return GRIB_NOT_FOUND;
if (k->values_count > *size)
return GRIB_ARRAY_TOO_SMALL;
kv = k->values;
while (kv) {
if (kv->value == NULL)
return GRIB_IO_PROBLEM;
values[i++] = grib_context_strdup(index->context, kv->value);
kv = kv->next;
}
*size = k->values_count;
qsort(values, *size, sizeof(char*), &compare_string);
return GRIB_SUCCESS;
}
int grib_index_get_long(const grib_index* index, const char* key, long* values, size_t* size)
{
grib_index_key* k = index->keys;
grib_string_list* kv;
int i = 0;
while (k && strcmp(k->name, key))
k = k->next;
if (!k)
return GRIB_NOT_FOUND;
if (k->type != GRIB_TYPE_LONG) {
grib_context_log(index->context, GRIB_LOG_ERROR, "Unable to get index %s as long", key);
return GRIB_WRONG_TYPE;
}
if (k->values_count > *size)
return GRIB_ARRAY_TOO_SMALL;
kv = k->values;
while (kv) {
if (strcmp(kv->value, GRIB_KEY_UNDEF))
values[i++] = atol(kv->value);
else
values[i++] = UNDEF_LONG;
kv = kv->next;
}
*size = k->values_count;
qsort(values, *size, sizeof(long), &compare_long);
return GRIB_SUCCESS;
}
int grib_index_get_double(const grib_index* index, const char* key, double* values, size_t* size)
{
grib_index_key* k = index->keys;
grib_string_list* kv;
int i = 0;
while (k && strcmp(k->name, key))
k = k->next;
if (!k)
return GRIB_NOT_FOUND;
if (k->type != GRIB_TYPE_DOUBLE) {
grib_context_log(index->context, GRIB_LOG_ERROR, "Unable to get index %s as double", key);
return GRIB_WRONG_TYPE;
}
if (k->values_count > *size)
return GRIB_ARRAY_TOO_SMALL;
kv = k->values;
while (kv) {
if (strcmp(kv->value, GRIB_KEY_UNDEF))
values[i++] = atof(kv->value);
else
values[i++] = UNDEF_DOUBLE;
kv = kv->next;
}
*size = k->values_count;
qsort(values, *size, sizeof(double), &compare_double);
return GRIB_SUCCESS;
}
int grib_index_select_long(grib_index* index, const char* skey, long value)
{
grib_index_key* key = NULL;
int err = GRIB_NOT_FOUND;
if (!index) {
grib_context* c = grib_context_get_default();
grib_context_log(c, GRIB_LOG_ERROR, "null index pointer");
return GRIB_INTERNAL_ERROR;
}
index->orderby = 0;
key = index->keys;
while (key) {
if (!strcmp(key->name, skey)) {
err = 0;
break;
}
key = key->next;
}
if (err) {
grib_context_log(index->context, GRIB_LOG_ERROR,
"key \"%s\" not found in index", skey);
return err;
}
ECCODES_ASSERT(key);
snprintf(key->value, sizeof(key->value), "%ld", value);
grib_index_rewind(index);
return 0;
}
int grib_index_select_double(grib_index* index, const char* skey, double value)
{
grib_index_key* key = NULL;
int err = GRIB_NOT_FOUND;
if (!index) {
grib_context* c = grib_context_get_default();
grib_context_log(c, GRIB_LOG_ERROR, "null index pointer");
return GRIB_INTERNAL_ERROR;
}
index->orderby = 0;
key = index->keys;
while (key) {
if (!strcmp(key->name, skey)) {
err = 0;
break;
}
key = key->next;
}
if (err) {
grib_context_log(index->context, GRIB_LOG_ERROR,
"key \"%s\" not found in index", skey);
return err;
}
ECCODES_ASSERT(key);
snprintf(key->value, sizeof(key->value), "%g", value);
grib_index_rewind(index);
return 0;
}
int grib_index_select_string(grib_index* index, const char* skey, const char* value)
{
grib_index_key* key = NULL;
int err = GRIB_NOT_FOUND;
if (!index) {
grib_context* c = grib_context_get_default();
grib_context_log(c, GRIB_LOG_ERROR, "null index pointer");
return GRIB_INTERNAL_ERROR;
}
index->orderby = 0;
key = index->keys;
while (key) {
if (!strcmp(key->name, skey)) {
err = 0;
break;
}
key = key->next;
}
if (err) {
grib_context_log(index->context, GRIB_LOG_ERROR,
"key \"%s\" not found in index", skey);
return err;
}
ECCODES_ASSERT(key);
snprintf(key->value, sizeof(key->value), "%s", value);
grib_index_rewind(index);
return 0;
}
grib_handle* codes_index_get_handle(grib_field* field, int message_type, int* err)
{
grib_handle* h = NULL;
typedef grib_handle* (*message_new_proc)(grib_context*, FILE*, int*);
message_new_proc message_new = NULL;
if (!field->file) {
grib_context_log(grib_context_get_default(), GRIB_LOG_ERROR, "codes_index_get_handle: NULL file handle");
*err = GRIB_INTERNAL_ERROR;
return NULL;
}
grib_file_open(field->file->name, "r", err);
if (*err != GRIB_SUCCESS)
return NULL;
switch (message_type) {
case CODES_GRIB:
message_new = codes_grib_handle_new_from_file;
break;
case CODES_BUFR:
message_new = codes_bufr_handle_new_from_file;
break;
default:
grib_context_log(grib_context_get_default(), GRIB_LOG_ERROR, "codes_index_get_handle: invalid message type");
*err = GRIB_INTERNAL_ERROR;
return NULL;
}
fseeko(field->file->handle, field->offset, SEEK_SET);
h = message_new(0, field->file->handle, err);
if (*err != GRIB_SUCCESS)
return NULL;
grib_file_close(field->file->name, 0, err);
return h;
}
static int grib_index_execute(grib_index* index)
{
grib_index_key* keys = NULL;
grib_field_tree* fields;
if (!index)
return GRIB_INTERNAL_ERROR;
keys = index->keys;
fields = index->fields;
index->rewind = 0;
while (keys) {
char* value;
if (keys->value[0])
value = keys->value;
else {
grib_context_log(index->context, GRIB_LOG_ERROR,
"please select a value for index key \"%s\"",
keys->name);
return GRIB_NOT_FOUND;
}
while (fields && strcmp(fields->value, value))
fields = fields->next;
if (fields && !strcmp(fields->value, value)) {
if (fields->next_level) {
keys = keys->next;
fields = fields->next_level;
}
else {
index->current = index->fieldset;
while (index->current->next)
index->current = index->current->next;
index->current->field = fields->field;
return 0;
}
}
else
return GRIB_END_OF_INDEX;
}
return 0;
}
static void grib_dump_key_values(FILE* fout, grib_string_list* values)
{
grib_string_list* sl = values;
int first = 1; /* boolean for commas */
fprintf(fout, "values = ");
while (sl) {
if (!first) {
fprintf(fout, ", ");
}
fprintf(fout, "%s", sl->value);
first = 0;
sl = sl->next;
}
fprintf(fout, "\n");
}
static void grib_dump_index_keys(FILE* fout, grib_index_key* keys, unsigned long flags)
{
if (!keys)
return;
fprintf(fout, "key name = %s\n", keys->name);
if ((flags & GRIB_DUMP_FLAG_TYPE) != 0) {
fprintf(fout, "key type = %s\n", grib_get_type_name(keys->type));
}
grib_dump_key_values(fout, keys->values);
grib_dump_index_keys(fout, keys->next, flags);
}
#ifdef INDEX_DUMPS
static void grib_dump_files(FILE* fout, grib_file* files)
{
if (!files) return;
fprintf(fout, "file = %s\n", files->name);
fprintf(fout, "ID = %d\n", files->id);
grib_dump_files(fout, files->next);
}
static void grib_dump_field(FILE* fout, grib_field* field)
{
if (!field) return;
fprintf(fout, "field name = %s\n", field->file->name);
/*fprintf(fout, "field FID = %d\n", field->file->id);
* fprintf(fout, "field offset = %ld\n", field->offset);
* fprintf(fout, "field length = %ld\n", field->length);
*/
grib_dump_field(fout, field->next);
}
static void grib_dump_field_tree(FILE* fout, grib_field_tree* tree)
{
if(!tree) return;
grib_dump_field(fout,tree->field);
fprintf(fout, "tree value = %s\n", tree->value);
grib_dump_field_tree(fout,tree->next_level);
grib_dump_field_tree(fout,tree->next);
}
#endif
int grib_index_dump_file(FILE* fout, const char* filename, unsigned long flags)
{
int err = 0;
grib_index* index = NULL;
grib_context* c = grib_context_get_default();
FILE* fh = NULL;
ECCODES_ASSERT(fout);
ECCODES_ASSERT(filename);
index = grib_index_read(c, filename, &err);
if (err)
return err;
/* To get the GRIB files referenced we have */
/* to resort to low level reading of the index file! */
fh = fopen(filename, "r");
if (fh) {
grib_file *file, *f;
unsigned char marker = 0;
char* identifier = grib_read_string(c, fh, &err);
if (err)
return err;
grib_context_free(c, identifier);
err = grib_read_uchar(fh, &marker);
if (err)
return err;
file = grib_read_files(c, fh, &err);
if (err)
return err;
f = file;
while (f) {
grib_file* prev = f;
fprintf(fout, "%s File: %s\n",
index->product_kind == PRODUCT_GRIB ? "GRIB" : "BUFR", f->name);
grib_context_free(c, f->name);
f = f->next;
grib_context_free(c, prev);
}
fclose(fh);
}
grib_index_dump(fout, index, flags);
grib_index_delete(index);
return GRIB_SUCCESS;
}
void grib_index_dump(FILE* fout, grib_index* index, unsigned long flags)
{
if (!index)
return;
ECCODES_ASSERT(fout);
/* The grib_dump_files does not print anything as */
/* the index object does not store the file names! */
/* grib_dump_files(fout, index->files); */
fprintf(fout, "Index keys:\n");
grib_dump_index_keys(fout, index->keys, flags);
/*
* fprintf(fout, "Index field tree:\n");
* grib_dump_field_tree(fout, index->fields);
*/
fprintf(fout, "Index count = %d\n", index->count);
}
char* grib_get_field_file(grib_index* index, off_t* offset)
{
char* file = NULL;
if (index && index->current && index->current->field) {
file = index->current->field->file->name;
*offset = index->current->field->offset;
}
return file;
}
grib_handle* grib_handle_new_from_index(grib_index* index, int* err)
{
ProductKind pkind = index->product_kind;
if (pkind == PRODUCT_GRIB)
return codes_new_from_index(index, CODES_GRIB, err);
if (pkind == PRODUCT_BUFR)
return codes_new_from_index(index, CODES_BUFR, err);
return NULL;
}
grib_handle* codes_new_from_index(grib_index* index, int message_type, int* err)
{
/*grib_index_key* keys;*/
grib_field_list *fieldset, *next;
grib_handle* h = NULL;
grib_context* c = NULL;
*err = 0;
if (!index)
return NULL;
c = index->context;
if (!index->rewind) {
// ECC-1764
if (!index->current || !index->current->field) {
*err = GRIB_END_OF_INDEX;
return NULL;
}
if (index->current->field->next)
index->current->field = index->current->field->next;
else if (index->current->next)
index->current = index->current->next;
else {
*err = GRIB_END_OF_INDEX;
return NULL;
}
h = codes_index_get_handle(index->current->field, message_type, err);
return h;
}
if (!index->fieldset) {
index->fieldset = (grib_field_list*)grib_context_malloc_clear(index->context,
sizeof(grib_field_list));
if (!index->fieldset) {
grib_context_log(index->context, GRIB_LOG_ERROR,
"Unable to allocate %zu bytes", sizeof(grib_field_list));
return NULL;
}
index->current = index->fieldset;
}
else {
fieldset = index->fieldset;
while (fieldset->next) {
next = fieldset->next;
grib_context_free(c, fieldset);
fieldset = next;
}
fieldset->field = NULL;
fieldset->next = NULL;
index->fieldset = fieldset;
index->current = fieldset;
}
*err = GRIB_END_OF_INDEX;
h = NULL;
/*keys=index->keys;*/
if ((*err = grib_index_execute(index)) == GRIB_SUCCESS) {
if (!index->fieldset) {
*err = GRIB_END_OF_INDEX;
return NULL;
}
index->current = index->fieldset;
h = codes_index_get_handle(index->current->field, message_type, err);
}
return h;
}
void grib_index_rewind(grib_index* index)
{
index->rewind = 1;
}
// static grib_index_key* search_key(grib_index_key* keys, grib_index_key* to_search)
// {
// if (!keys || !strcmp(keys->name, to_search->name))
// return keys;
// return search_key(keys->next, to_search);
// }
// int grib_index_search(grib_index* index, grib_index_key* keys)
// {
// grib_index_key* ki = index->keys;
// grib_index_key* ks = keys;
// while (ks) {
// ki = search_key(ki, ks);
// if (!ki) {
// ki = index->keys;
// ki = search_key(ki, ks);
// }
// if (ki)
// snprintf(ki->value, 1024, "%s", ks->value);
// ks = ks->next;
// }
// grib_index_rewind(index);
// return 0;
// }
int codes_index_set_product_kind(grib_index* index, ProductKind product_kind)
{
if (!index)
return GRIB_INVALID_ARGUMENT;
if (product_kind == PRODUCT_GRIB || product_kind == PRODUCT_BUFR) {
index->product_kind = product_kind;
} else {
return GRIB_INVALID_ARGUMENT;
}
return GRIB_SUCCESS;
}
int codes_index_set_unpack_bufr(grib_index* index, int unpack)
{
if (!index)
return GRIB_INVALID_ARGUMENT;
if (index->product_kind != PRODUCT_BUFR)
return GRIB_INVALID_ARGUMENT;
index->unpack_bufr = unpack;
return GRIB_SUCCESS;
}
/* Return 1 if the file is an index file. 0 otherwise */
int is_index_file(const char* filename)
{
FILE* fh;
char buf[8] = {0,};
/* Only read the first 6 characters of identifier. Exclude version */
const size_t numChars = 6;
const char* id_grib = "GRBIDX";
const char* id_bufr = "BFRIDX";
int ret = 0;
size_t size = 0;
fh = fopen(filename, "r");
if (!fh)
return 0;
size = fread(buf, 1, 1, fh);
if (size != 1) {
fclose(fh);
return 0;
}
size = fread(buf, numChars, 1, fh);
if (size != 1) {
fclose(fh);
return 0;
}
ret = (strcmp(buf, id_grib)==0 || strcmp(buf, id_bufr)==0);
fclose(fh);
return ret;
}