eccodes/src/grib_accessor.c

860 lines
22 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.
*/
/***************************************************************************
* Jean Baptiste Filippi - 01.11.2005
* Enrico Fucile
* *
***************************************************************************/
#include "grib_api_internal.h"
/* Note: A fast cut-down version of strcmp which does NOT return -1 */
/* 0 means input strings are equal and 1 means not equal */
GRIB_INLINE static int grib_inline_strcmp(const char* a,const char* b) {
if (*a != *b) return 1;
while((*a!=0 && *b!=0) && *(a) == *(b) ) {a++;b++;}
return (*a==0 && *b==0) ? 0 : 1;
}
void grib_accessor_dump(grib_accessor* a, grib_dumper* f)
{
grib_accessor_class *c = a->cclass;
while(c)
{
if(c->dump)
{
c->dump(a, f);
return;
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
}
int grib_pack_missing(grib_accessor* a)
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is packing (double) %g",(a->parent->owner)?(a->parent->owner->name):"root", a->name ,v?(*v):0); */
while(c)
{
if(c->pack_missing)
{
return c->pack_missing(a);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_pack_zero(grib_accessor* a)
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is packing (double) %g",(a->parent->owner)?(a->parent->owner->name):"root", a->name ,v?(*v):0); */
while(c)
{
if(c->clear)
{
return c->clear(a);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_is_missing_internal(grib_accessor* a)
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is packing (double) %g",(a->parent->owner)?(a->parent->owner->name):"root", a->name ,v?(*v):0); */
while(c)
{
if(c->is_missing)
{
return c->is_missing(a);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_pack_double(grib_accessor* a, const double* v, size_t *len )
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is packing (double) %g",(a->parent->owner)?(a->parent->owner->name):"root", a->name ,v?(*v):0); */
while(c)
{
if(c->pack_double)
{
return c->pack_double(a,v,len);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_pack_expression(grib_accessor* a, grib_expression *e )
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is packing (double) %g",(a->parent->owner)?(a->parent->owner->name):"root", a->name ,v?(*v):0); */
while(c)
{
if(c->pack_expression)
{
return c->pack_expression(a,e);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_pack_string(grib_accessor* a, const char* v, size_t *len )
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is packing (string) %s",(a->parent->owner)?(a->parent->owner->name):"root", a->name ,v?v:"(null)");*/
while(c)
{
if(c->pack_string)
{
return c->pack_string(a,v,len);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_pack_string_array(grib_accessor* a, const char** v, size_t *len )
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is packing (string) %s",(a->parent->owner)?(a->parent->owner->name):"root", a->name ,v?v:"(null)");*/
while(c)
{
if(c->pack_string_array)
{
return c->pack_string_array(a,v,len);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_pack_long(grib_accessor* a,const long* v, size_t *len )
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is packing (long) %d",(a->parent->owner)?(a->parent->owner->name):"root", a->name ,v?(*v):0); */
while(c)
{
if(c->pack_long)
{
return c->pack_long(a,v,len);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_pack_bytes(grib_accessor* a, const unsigned char* v, size_t *len )
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is packing (bytes) %d",(a->parent->owner)?(a->parent->owner->name):"root", a->name ,v?(*v):0); */
while(c)
{
if(c->pack_bytes)
{
return c->pack_bytes(a,v,len);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_unpack_bytes(grib_accessor* a, unsigned char* v, size_t *len )
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is unpacking (bytes)",(a->parent->owner)?(a->parent->owner->name):"root", a->name ); */
while(c)
{
if(c->unpack_bytes)
{
return c->unpack_bytes(a,v,len);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_unpack_double_subarray(grib_accessor* a, double* v, size_t start, size_t len )
{
grib_accessor_class *c = a->cclass;
while(c)
{
if(c->unpack_double_subarray)
{
return c->unpack_double_subarray(a,v,start,len);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_unpack_double(grib_accessor* a, double* v, size_t *len )
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is unpacking (double)",(a->parent->owner)?(a->parent->owner->name):"root", a->name ); */
while(c)
{
if(c->unpack_double)
{
return c->unpack_double(a,v,len);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_unpack_double_element(grib_accessor* a, size_t i ,double* v )
{
grib_accessor_class *c = a->cclass;
while(c)
{
if(c->unpack_double_element)
{
return c->unpack_double_element(a,i,v);
}
c = c->super ? *(c->super) : NULL;
}
return GRIB_NOT_IMPLEMENTED;
}
int grib_unpack_string(grib_accessor* a, char* v, size_t *len )
{
grib_accessor_class *c = a->cclass;
/* grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is unpacking (string)",(a->parent->owner)?(a->parent->owner->name):"root", a->name ); */
while(c)
{
if(c->unpack_string)
{
return c->unpack_string(a,v,len);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_unpack_string_array(grib_accessor* a, char** v, size_t *len )
{
grib_accessor_class *c = a->cclass;
while(c)
{
if(c->unpack_string_array)
{
return c->unpack_string_array(a,v,len);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_accessors_list_unpack_long(grib_accessors_list* al,long* val,size_t* buffer_len)
{
int err=GRIB_SUCCESS;
size_t unpacked_len=0;
size_t len=0;
while (al && err==GRIB_SUCCESS ) {
len=*buffer_len-unpacked_len;
err=grib_unpack_long(al->accessor, val + unpacked_len, &len);
unpacked_len += len;
al=al->next;
}
*buffer_len=unpacked_len;
return err;
}
int grib_accessors_list_unpack_double(grib_accessors_list* al,double* val,size_t* buffer_len)
{
int err=GRIB_SUCCESS;
size_t unpacked_len=0;
size_t len=0;
while (al && err==GRIB_SUCCESS ) {
len=*buffer_len-unpacked_len;
err=grib_unpack_double(al->accessor, val + unpacked_len, &len);
unpacked_len += len;
al=al->next;
}
*buffer_len=unpacked_len;
return err;
}
int grib_accessors_list_unpack_string(grib_accessors_list* al,char** val,size_t* buffer_len)
{
int err=GRIB_SUCCESS;
size_t unpacked_len=0;
size_t len=0;
while (al && err==GRIB_SUCCESS ) {
len=*buffer_len-unpacked_len;
err=grib_unpack_string_array(al->accessor, val + unpacked_len, &len);
unpacked_len += len;
al=al->next;
}
*buffer_len=unpacked_len;
return err;
}
int grib_unpack_long(grib_accessor* a,long* v, size_t *len )
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is unpacking (long)",(a->parent->owner)?(a->parent->owner->name):"root", a->name ); */
while(c)
{
if(c->unpack_long)
{
return c->unpack_long(a,v,len);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
long grib_accessor_get_native_type(grib_accessor* a)
{
grib_accessor_class *c = NULL;
if (a) c = a->cclass;
while(c)
{
if(c->get_native_type)
return c->get_native_type(a);
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
long grib_get_next_position_offset(grib_accessor* a)
{
grib_accessor_class *c = NULL;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is checking next (long)",(a->parent->owner)?(a->parent->owner->name):"root", a->name ); */
if (a) c = a->cclass;
while(c)
{
if(c->next_offset)
return c->next_offset(a);
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
long grib_string_length(grib_accessor* a)
{
grib_accessor_class *c = NULL;
if (a) c = a->cclass;
while(c)
{
if(c->string_length)
return c->string_length(a);
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
long grib_byte_offset(grib_accessor* a)
{
grib_accessor_class *c = NULL;
if (a) c = a->cclass;
while(c)
{
if(c->byte_offset)
return c->byte_offset(a);
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
long grib_byte_count(grib_accessor* a)
{
grib_accessor_class *c = NULL;
if (a) c = a->cclass;
while(c)
{
if(c->byte_count)
return c->byte_count(a);
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_value_count(grib_accessor* a,long* count)
{
grib_accessor_class *c = NULL;
int err = 0;
if (a) c = a->cclass;
while(c)
{
if(c->value_count) {
err = c->value_count(a, count);
return err;
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
int grib_accessors_list_value_count(grib_accessors_list* al,size_t* count)
{
long lcount=0;
*count=0;
while (al) {
grib_value_count(al->accessor,&lcount);
*count+=lcount;
al=al->next;
}
return 0;
}
int grib_accessor_notify_change(grib_accessor* a,grib_accessor* changed)
{
grib_accessor_class *c = NULL;
if (a) c = a->cclass;
while(c)
{
if(c->notify_change)
return c->notify_change(a,changed);
c = c->super ? *(c->super) : NULL;
}
if (a) printf("notify_change not implemented for %s %s\n",a->cclass->name, a->name);
Assert(0);
return 0;
}
/* For this one, ALL init are called */
static void init_accessor(grib_accessor_class* c,grib_accessor* a, const long len, grib_arguments* args)
{
if(c) {
grib_accessor_class *s = c->super ? *(c->super) : NULL;
init_accessor(s,a,len,args);
if(c->init) c->init(a,len, args);
}
}
void grib_init_accessor(grib_accessor* a, const long len, grib_arguments* args)
{
init_accessor(a->cclass,a,len,args);
}
#if 0
static void post_init_accessor(grib_accessor_class* c,grib_accessor* a)
{
if(c) {
grib_accessor_class *s = c->super ? *(c->super) : NULL;
post_init_accessor(s,a);
if(c->post_init) c->post_init(a);
}
}
#endif
/* For this one, ALL destroy are called */
void grib_accessor_delete(grib_context *ct, grib_accessor* a)
{
grib_accessor_class *c = a->cclass;
while(c)
{
grib_accessor_class *s = c->super ? *(c->super) : NULL;
/*grib_context_log(ct,GRIB_LOG_DEBUG,"destroy %s ==> %s",c->name,a->name);*/
if(c->destroy) {
c->destroy(ct,a);
}
c = s;
}
/*printf("Debug: grib_accessor_delete a=%p (%s)\n", (void*)a, a->name);*/
grib_context_free(ct,a);
}
grib_accessor* grib_accessor_clone(grib_accessor* a,grib_section* s,int* err)
{
grib_accessor_class *c = a->cclass;
grib_context* ct=a->context;
while(c)
{
grib_accessor_class *super = c->super ? *(c->super) : NULL;
grib_context_log(ct,GRIB_LOG_DEBUG,"clone %s ==> %s",c->name,a->name);
if(c->make_clone) {
return c->make_clone(a,s,err);
}
c = super;
}
return 0;
}
void grib_update_size(grib_accessor* a, size_t len )
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is packing (double) %g",(a->parent->owner)?(a->parent->owner->name):"root", a->name ,v?(*v):0); */
while(c)
{
if(c->update_size)
{
c->update_size(a,len);
return;
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
}
int grib_nearest_smaller_value(grib_accessor* a,double val,double* nearest)
{
grib_accessor_class *c = a->cclass;
while(c)
{
if(c->nearest_smaller_value)
{
return c->nearest_smaller_value(a,val,nearest);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
size_t grib_preferred_size(grib_accessor* a,int from_handle)
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is packing (long) %d",(a->parent->owner)?(a->parent->owner->name):"root", a->name ,v?(*v):0); */
while(c)
{
if(c->preferred_size)
{
return c->preferred_size(a,from_handle);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
grib_accessor* grib_next_accessor(grib_accessor* a)
{
grib_accessor_class *c = a->cclass;
while(c)
{
if(c->next)
{
return c->next(a,1);
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return 0;
}
void grib_resize(grib_accessor* a,size_t new_size)
{
grib_accessor_class *c = a->cclass;
/*grib_context_log(a->context, GRIB_LOG_DEBUG, "(%s)%s is packing (long) %d",(a->parent->owner)?(a->parent->owner->name):"root", a->name ,v?(*v):0); */
while(c)
{
if(c->resize)
{
c->resize(a,new_size);
return ;
}
c = c->super ? *(c->super) : NULL;
}
Assert(0);
return;
}
int grib_compare_accessors(grib_accessor* a1,grib_accessor* a2,int compare_flags)
{
int ret=0;
long type1=0;
long type2=0;
int type_mismatch=0;
grib_accessor_class *c1=NULL;
if ((compare_flags & GRIB_COMPARE_NAMES) && grib_inline_strcmp(a1->name,a2->name))
return GRIB_NAME_MISMATCH;
if ( compare_flags & GRIB_COMPARE_TYPES ) {
type1=grib_accessor_get_native_type( a1 );
type2=grib_accessor_get_native_type( a2 );
type_mismatch = type1 != type2 ? 1 : 0;
}
ret=GRIB_UNABLE_TO_COMPARE_ACCESSORS;
c1 = a1->cclass;
while(c1)
{
if(c1->compare)
{
ret = c1->compare(a1, a2);
break;
}
c1 = c1->super ? *(c1->super) : NULL;
}
if (ret == GRIB_VALUE_MISMATCH && type_mismatch)
ret = GRIB_TYPE_AND_VALUE_MISMATCH;
return ret;
}
const char* grib_get_type_name(int type)
{
switch(type)
{
case GRIB_TYPE_LONG: return "long"; break;
case GRIB_TYPE_STRING: return "string"; break;
case GRIB_TYPE_BYTES: return "bytes"; break;
case GRIB_TYPE_DOUBLE: return "double"; break;
case GRIB_TYPE_LABEL: return "label"; break;
case GRIB_TYPE_SECTION: return "section"; break;
}
return "unknown";
}
/*
int grib_accessor_clear_attributes(grib_accessor* a)
{
int id;
for (id=0;id<MAX_ACCESSOR_ATTRIBUTES;id++) {
a->attributes[id]=NULL;
}
return 0;
}
*/
int grib_accessor_add_attribute(grib_accessor* a,grib_accessor* attr,int nest_if_clash)
{
int id=0;
int idx=0;
grib_accessor* same=NULL;
grib_accessor* aloc=a;
if(grib_accessor_has_attributes(a)) {
same=_grib_accessor_get_attribute(a,attr->name,&id);
}
if (same) {
if (nest_if_clash==0) return GRIB_ATTRIBUTE_CLASH;
aloc=same;
}
for (id=0;id<MAX_ACCESSOR_ATTRIBUTES;id++) {
if (aloc->attributes[id] == NULL) {
/* attr->parent=a->parent; */
aloc->attributes[id]=attr;
attr->parent_as_attribute=aloc;
if (aloc->same)
attr->same=_grib_accessor_get_attribute(aloc->same,attr->name,&idx);
grib_context_log(a->context,GRIB_LOG_DEBUG,"added attribute %s->%s",a->name,attr->name);
return GRIB_SUCCESS;
}
}
return GRIB_TOO_MANY_ATTRIBUTES;
}
int grib_accessor_replace_attribute(grib_accessor* a,grib_accessor* attr)
{
int id=0;
int idx=0;
if (_grib_accessor_get_attribute(a,attr->name,&id) != NULL) {
grib_accessor_delete(a->context,a->attributes[id]);
a->attributes[id]=attr;
attr->parent_as_attribute=a;
if (a->same)
attr->same=_grib_accessor_get_attribute(a->same,attr->name,&idx);
} else {
grib_accessor_add_attribute(a,attr,0);
}
return GRIB_SUCCESS;
}
int grib_accessor_delete_attribute(grib_accessor* a,const char* name)
{
int id=0;
if (_grib_accessor_get_attribute(a,name,&id) != NULL) {
grib_accessor_delete(a->context,a->attributes[id]);
a->attributes[id]=NULL;
return GRIB_SUCCESS;
} else {
return GRIB_NOT_FOUND;
}
}
grib_accessor* grib_accessor_get_attribute_by_index(grib_accessor* a,int index)
{
if (index<MAX_ACCESSOR_ATTRIBUTES) return a->attributes[index];
return NULL;
}
const char* grib_accessor_get_name(grib_accessor* a) {
return a->name;
}
grib_accessor* _grib_accessor_get_attribute(grib_accessor* a,const char* name,int* index)
{
int i=0;
while (i<MAX_ACCESSOR_ATTRIBUTES && a->attributes[i]) {
if (!grib_inline_strcmp(a->attributes[i]->name,name)) {
*index=i;
return a->attributes[i];
}
i++;
}
return NULL;
}
int grib_accessor_has_attributes(grib_accessor* a)
{
return a->attributes[0] ? 1 : 0 ;
}
grib_accessor* grib_accessor_get_attribute(grib_accessor* a,const char* name)
{
int index=0;
char* p=0;
char* basename=NULL;
char* attribute_name=NULL;
grib_accessor* acc=NULL;
p=(char*)name;
while ( *(p+1) != '\0' && ( *p != '-' || *(p+1)!= '>' ) ) p++;
if (*(p+1) == '\0') {
return _grib_accessor_get_attribute(a,name,&index);
} else {
size_t size=p-name;
attribute_name=p+2;
basename=(char*)grib_context_malloc_clear(a->context,size+1);
basename=(char*)memcpy(basename,name,size);
acc=_grib_accessor_get_attribute(a,basename,&index);
grib_context_free(a->context,basename);
if (acc) return grib_accessor_get_attribute(acc,attribute_name);
else return NULL;
}
}
grib_accessors_list* grib_accessors_list_create(grib_context* c)
{
return (grib_accessors_list*)grib_context_malloc_clear(c,sizeof(grib_accessors_list));
}
void grib_accessors_list_push(grib_accessors_list* al,grib_accessor* a,int rank)
{
grib_accessors_list* last;
grib_context* c=a->context;
last=grib_accessors_list_last(al);
if (last && last->accessor) {
last->next=(grib_accessors_list*)grib_context_malloc_clear(c,sizeof(grib_accessors_list));
last->next->accessor=a;
last->next->prev=last;
last->next->rank=rank;
al->last=last->next;
} else {
al->accessor=a;
al->rank=rank;
al->last=al;
}
}
grib_accessors_list* grib_accessors_list_last(grib_accessors_list* al)
{
/*grib_accessors_list* last=al;*/
/*grib_accessors_list* next=al->next;*/
/*
while(next) {
last=next;
next=last->next;
}
*/
return al->last;
}
grib_accessors_list* grib_accessors_list_find(grib_accessors_list* al,grib_accessor* a)
{
grib_accessors_list* last=al;
grib_accessors_list* next=al->next;
while(next) {
if (last->accessor == a) return last;
last=next;
next=last->next;
}
return NULL;
}
void grib_accessors_list_delete(grib_context* c,grib_accessors_list* al)
{
grib_accessors_list* tmp;
while (al) {
tmp=al->next;
/*grib_accessor_delete(c, al->accessor);*/
grib_context_free(c,al);
al=tmp;
}
}
#if 0
void grib_print_accessor_flags(const grib_accessor* acc)
{
const unsigned long f = acc->flags;
if (f & GRIB_ACCESSOR_FLAG_READ_ONLY) printf("READ_ONLY ");
if (f & GRIB_ACCESSOR_FLAG_DUMP) printf("DUMP ");
if (f & GRIB_ACCESSOR_FLAG_EDITION_SPECIFIC) printf("EDITION_SPECIFIC ");
if (f & GRIB_ACCESSOR_FLAG_CAN_BE_MISSING) printf("CAN_BE_MISSING ");
if (f & GRIB_ACCESSOR_FLAG_LOWERCASE) printf("LOWERCASE ");
if (f & GRIB_ACCESSOR_FLAG_HIDDEN) printf("HIDDEN ");
/* TODO: the rest */
}
#endif