mirror of https://github.com/ecmwf/eccodes.git
1749 lines
46 KiB
C
1749 lines
46 KiB
C
/*
|
|
* Copyright 2005-2018 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.
|
|
*/
|
|
|
|
/*
|
|
*
|
|
* Description: grib index
|
|
*
|
|
*/
|
|
|
|
#include "grib_api_internal.h"
|
|
|
|
#define UNDEF_LONG -99999
|
|
#define UNDEF_DOUBLE -99999
|
|
|
|
#define NULL_MARKER 0
|
|
#define NOT_NULL_MARKER 255
|
|
|
|
|
|
/* #if GRIB_PTHREADS */
|
|
#if 0
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
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 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;
|
|
|
|
grib_index_fields_compress(c,index->fields,0,0,compress);
|
|
|
|
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 %d 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 %d 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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
int grib_write_short(FILE* fh,short val)
|
|
{
|
|
if (fwrite(&val,sizeof(short),1,fh)<1)
|
|
return GRIB_IO_PROBLEM;
|
|
return GRIB_SUCCESS;
|
|
}
|
|
|
|
int grib_write_long(FILE* fh,long val)
|
|
{
|
|
if (fwrite(&val,sizeof(long),1,fh)<1)
|
|
return GRIB_IO_PROBLEM;
|
|
return GRIB_SUCCESS;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
int grib_write_identifier(FILE* fh)
|
|
{
|
|
return grib_write_string(fh,"GRBIDX1");
|
|
}
|
|
|
|
int grib_write_null_marker(FILE* fh)
|
|
{
|
|
return grib_write_uchar(fh,NULL_MARKER);
|
|
}
|
|
|
|
int grib_write_not_null_marker(FILE* fh)
|
|
{
|
|
return grib_write_uchar(fh,NOT_NULL_MARKER);
|
|
}
|
|
|
|
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 ;
|
|
unsigned long offset;
|
|
unsigned long length;
|
|
|
|
*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;
|
|
|
|
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 long values_count=0;
|
|
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)
|
|
{
|
|
if (!field_list) return;
|
|
grib_context_free(c,field_list);
|
|
}
|
|
|
|
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;
|
|
|
|
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;
|
|
}
|
|
|
|
err=grib_write_identifier(fh);
|
|
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;
|
|
|
|
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;
|
|
}
|
|
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->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);
|
|
return index;
|
|
}
|
|
|
|
int grib_index_search_same(grib_index* index, grib_handle* h)
|
|
{
|
|
int err=0;
|
|
char buf[1024]={0,};
|
|
size_t buflen=1024;
|
|
grib_index_key* keys;
|
|
long lval=0;
|
|
double dval=0.0;
|
|
grib_context* c;
|
|
|
|
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=1024;
|
|
switch (keys->type) {
|
|
case GRIB_TYPE_STRING:
|
|
err=grib_get_string(h,keys->name,buf,&buflen);
|
|
if (err==GRIB_NOT_FOUND) sprintf(buf,GRIB_KEY_UNDEF);
|
|
break;
|
|
case GRIB_TYPE_LONG:
|
|
err=grib_get_long(h,keys->name,&lval);
|
|
if (err==GRIB_NOT_FOUND) sprintf(buf,GRIB_KEY_UNDEF);
|
|
else sprintf(buf,"%ld",lval);
|
|
break;
|
|
case GRIB_TYPE_DOUBLE:
|
|
err=grib_get_double(h,keys->name,&dval);
|
|
if (err==GRIB_NOT_FOUND) sprintf(buf,GRIB_KEY_UNDEF);
|
|
else sprintf(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;
|
|
}
|
|
sprintf(keys->value,"%s",buf);
|
|
keys=keys->next;
|
|
}
|
|
grib_index_rewind(index);
|
|
return 0;
|
|
}
|
|
|
|
int grib_index_add_file(grib_index* index,const char* filename) {
|
|
return _codes_index_add_file(index,filename,CODES_GRIB);
|
|
}
|
|
|
|
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);
|
|
Assert(0);
|
|
return NULL;
|
|
}
|
|
|
|
int _codes_index_add_file(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;
|
|
|
|
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=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++;
|
|
|
|
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) sprintf(buf,GRIB_KEY_UNDEF);
|
|
break;
|
|
case GRIB_TYPE_LONG:
|
|
err=grib_get_long(h,index_key->name,&lval);
|
|
if (err==GRIB_NOT_FOUND) sprintf(buf,GRIB_KEY_UNDEF);
|
|
else sprintf(buf,"%ld",lval);
|
|
break;
|
|
case GRIB_TYPE_DOUBLE:
|
|
err=grib_get_double(h,index_key->name,&dval);
|
|
if (err==GRIB_NOT_FOUND) sprintf(buf,GRIB_KEY_UNDEF);
|
|
else sprintf(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",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;
|
|
|
|
grib_handle_delete(h);
|
|
}
|
|
|
|
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;
|
|
}
|
|
return GRIB_SUCCESS;
|
|
}
|
|
|
|
#if 0
|
|
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) sprintf(buf,GRIB_KEY_UNDEF);
|
|
break;
|
|
case GRIB_TYPE_LONG:
|
|
err=grib_get_long(h,index_key->name,&lval);
|
|
if (err==GRIB_NOT_FOUND) sprintf(buf,GRIB_KEY_UNDEF);
|
|
else sprintf(buf,"%ld",lval);
|
|
break;
|
|
case GRIB_TYPE_DOUBLE:
|
|
err=grib_get_double(h,index_key->name,&dval);
|
|
if (err==GRIB_NOT_FOUND) sprintf(buf,GRIB_KEY_UNDEF);
|
|
else sprintf(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",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;
|
|
}
|
|
#endif
|
|
|
|
grib_index* grib_index_new_from_file(grib_context* c, 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(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(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(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(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;
|
|
}
|
|
Assert(key);
|
|
sprintf(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;
|
|
}
|
|
Assert(key);
|
|
sprintf(key->value,"%g",value);
|
|
grib_index_rewind(index);
|
|
return 0;
|
|
}
|
|
|
|
int grib_index_select_string(grib_index* index,const char* skey,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;
|
|
}
|
|
Assert(key);
|
|
sprintf(key->value,"%s",value);
|
|
grib_index_rewind(index);
|
|
return 0;
|
|
}
|
|
|
|
grib_handle* grib_index_get_handle(grib_field* field,int *err)
|
|
{
|
|
return codes_index_get_handle(field,CODES_GRIB,err);
|
|
}
|
|
|
|
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,int* );
|
|
message_new_proc message_new=NULL;
|
|
Assert(field->file);
|
|
grib_file_open(field->file->name,"r",err);
|
|
|
|
if (*err!=GRIB_SUCCESS) return NULL;
|
|
switch (message_type) {
|
|
case CODES_GRIB:
|
|
message_new=grib_new_from_file;
|
|
break;
|
|
case CODES_BUFR:
|
|
Assert(!"_codes_index_add_file for BUFR: not yet implemented");
|
|
/* message_new=bufr_new_from_file; */
|
|
break;
|
|
default :
|
|
Assert(0);
|
|
}
|
|
|
|
fseeko(field->file->handle,field->offset,SEEK_SET);
|
|
h=message_new(0,field->file->handle,0,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)
|
|
{
|
|
if (!keys) return;
|
|
fprintf(fout, "key name = %s\n", keys->name);
|
|
/* fprintf(fout, "key type = %d\n", keys->type); */
|
|
|
|
grib_dump_key_values(fout, keys->values);
|
|
grib_dump_index_keys(fout, keys->next);
|
|
}
|
|
#if 0
|
|
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)
|
|
{
|
|
int err = 0;
|
|
grib_index* index = NULL;
|
|
grib_context* c = grib_context_get_default();
|
|
FILE* fh = NULL;
|
|
|
|
Assert(fout);
|
|
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;
|
|
char* identifier=NULL;
|
|
unsigned char marker=0;
|
|
|
|
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) {
|
|
fprintf(fout, "GRIB File: %s\n", f->name);
|
|
f=f->next;
|
|
}
|
|
fclose(fh);
|
|
}
|
|
|
|
grib_index_dump(fout, index);
|
|
grib_index_delete(index);
|
|
|
|
return GRIB_SUCCESS;
|
|
}
|
|
|
|
void grib_index_dump(FILE* fout, grib_index* index)
|
|
{
|
|
if (!index) return;
|
|
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);
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
return codes_new_from_index(index,CODES_GRIB,err);
|
|
}
|
|
|
|
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;
|
|
|
|
if (!index) return NULL;
|
|
c=index->context;
|
|
if (!index->rewind) {
|
|
if (!index->current) {
|
|
*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 %d 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) sprintf(ki->value,"%s",ks->value);
|
|
ks=ks->next;
|
|
}
|
|
|
|
grib_index_rewind(index);
|
|
return 0;
|
|
}
|