eccodes/src/grib_accessor_class.cc

411 lines
13 KiB
C++
Raw Normal View History

2013-03-25 12:04:10 +00:00
/*
2020-01-28 14:32:34 +00:00
* (C) Copyright 2005- ECMWF.
2013-03-25 12:04:10 +00:00
*
* 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.
*/
2013-03-25 12:04:10 +00:00
#include "grib_api_internal.h"
#include "grib_accessor_classes_hash.cc"
2024-11-12 21:54:49 +00:00
//#include <iostream>
#include "accessor/grib_accessor.h"
2013-03-25 12:04:10 +00:00
#if GRIB_PTHREADS
2020-01-22 13:10:59 +00:00
static pthread_once_t once = PTHREAD_ONCE_INIT;
2013-03-25 12:04:10 +00:00
static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
static void init_mutex()
2020-01-22 13:10:59 +00:00
{
2013-03-25 12:04:10 +00:00
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
2020-01-22 13:10:59 +00:00
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex1, &attr);
2013-03-25 12:04:10 +00:00
pthread_mutexattr_destroy(&attr);
}
2015-12-30 14:39:02 +00:00
#elif GRIB_OMP_THREADS
static int once = 0;
static omp_nest_lock_t mutex1;
static void init_mutex()
2015-12-30 14:39:02 +00:00
{
GRIB_OMP_CRITICAL(lock_grib_accessor_class_c)
{
2020-01-22 13:10:59 +00:00
if (once == 0) {
2015-12-30 14:39:02 +00:00
omp_init_nest_lock(&mutex1);
once = 1;
}
}
}
2013-03-25 12:04:10 +00:00
#endif
struct table_entry
{
2022-04-08 14:10:53 +00:00
const char* type;
2020-01-22 13:10:59 +00:00
grib_accessor_class** cclass;
2013-03-25 12:04:10 +00:00
};
2018-05-18 18:06:50 +00:00
#ifdef ACCESSOR_FACTORY_USE_TRIE
2017-06-07 12:53:01 +00:00
/* Note: A fast cut-down version of strcmp which does NOT return -1 */
/* 0 means input strings are equal and 1 means not equal */
2020-01-22 13:10:59 +00:00
static GRIB_INLINE int grib_inline_strcmp(const char* a, const char* b)
2016-08-31 08:59:21 +00:00
{
2020-01-22 13:10:59 +00:00
if (*a != *b)
return 1;
while ((*a != 0 && *b != 0) && *(a) == *(b)) {
a++;
b++;
}
return (*a == 0 && *b == 0) ? 0 : 1;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static struct table_entry table[] = {
2016-08-31 08:59:21 +00:00
/* This file is generated by ./make_class.pl */
2013-03-25 12:04:10 +00:00
#include "grib_accessor_factory.h"
};
#endif /* ACCESSOR_FACTORY_USE_TRIE */
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
grib_section* grib_create_root_section(const grib_context* context, grib_handle* h)
2013-03-25 12:04:10 +00:00
{
2024-08-30 14:27:35 +00:00
const char* fpath = 0;
2020-01-22 13:10:59 +00:00
grib_section* s = (grib_section*)grib_context_malloc_clear(context, sizeof(grib_section));
2013-06-19 12:13:45 +00:00
GRIB_MUTEX_INIT_ONCE(&once, &init_mutex);
2013-06-19 12:13:45 +00:00
GRIB_MUTEX_LOCK(&mutex1);
2020-01-22 13:10:59 +00:00
if (h->context->grib_reader == NULL) {
if ((fpath = grib_context_full_defs_path(h->context, "boot.def")) == NULL) {
grib_context_log(h->context, GRIB_LOG_FATAL,
"Unable to find boot.def. Context path=%s\n"
"\nPossible causes:\n"
"- The software is not correctly installed\n"
"- The environment variable ECCODES_DEFINITION_PATH is defined but incorrect\n",
context->grib_definition_files_path);
2013-06-19 12:13:45 +00:00
}
2020-01-22 13:10:59 +00:00
grib_parse_file(h->context, fpath);
2013-03-25 12:04:10 +00:00
}
2013-06-19 12:13:45 +00:00
GRIB_MUTEX_UNLOCK(&mutex1);
2020-01-22 13:10:59 +00:00
s->h = h;
2013-06-19 12:13:45 +00:00
s->aclength = NULL;
s->owner = NULL;
2013-06-19 12:13:45 +00:00
s->block = (grib_block_of_accessors*)
2020-01-22 13:10:59 +00:00
grib_context_malloc_clear(context, sizeof(grib_block_of_accessors));
2013-06-19 12:13:45 +00:00
grib_context_log(context, GRIB_LOG_DEBUG, "Creating root section");
return s;
2013-03-25 12:04:10 +00:00
}
/* Only used if ACCESSOR_FACTORY_USE_TRIE */
2018-05-18 18:06:50 +00:00
#ifdef ACCESSOR_FACTORY_USE_TRIE
2020-01-22 13:10:59 +00:00
static GRIB_INLINE grib_accessor_class* get_class(grib_context* c, char* type)
{
2013-06-19 12:13:45 +00:00
int i;
2020-01-22 13:10:59 +00:00
int table_count = 0;
grib_accessor_class** the_class = NULL;
2013-06-19 12:13:45 +00:00
2020-01-22 13:10:59 +00:00
if ((the_class = (grib_accessor_class**)grib_trie_get(c->classes, type)) != NULL)
return *(the_class);
2013-06-19 12:13:45 +00:00
2024-01-30 12:08:46 +00:00
const int table_count = sizeof(table) / sizeof(table[0]);
2020-01-22 13:10:59 +00:00
for (i = 0; i < table_count; i++) {
if (grib_inline_strcmp(type, table[i].type) == 0) {
grib_trie_insert(c->classes, type, table[i].cclass);
2013-06-19 12:13:45 +00:00
return *(table[i].cclass);
}
}
grib_context_log(c, GRIB_LOG_ERROR, "ecCodes Version: %s\nDefinition files path: %s\n",
2020-01-22 13:10:59 +00:00
ECCODES_VERSION_STR, c->grib_definition_files_path);
grib_context_log(c, GRIB_LOG_FATAL, "unable to create class %s", type);
2013-06-19 12:13:45 +00:00
return NULL;
2013-03-25 12:04:10 +00:00
}
#endif /* ACCESSOR_FACTORY_USE_TRIE */
2013-03-25 12:04:10 +00:00
grib_accessor* grib_accessor_factory(grib_section* p, grib_action* creator,
2020-01-22 13:10:59 +00:00
const long len, grib_arguments* params)
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
grib_accessor* a = NULL;
size_t size = 0;
2013-06-19 12:13:45 +00:00
2024-09-16 16:04:08 +00:00
grib_accessor* builder = *((grib_accessor_hash(creator->op, strlen(creator->op)))->cclass);
a = builder->create_empty_accessor();
2013-06-19 12:13:45 +00:00
2024-08-11 23:54:29 +00:00
a->name_ = creator->name;
a->name_space_ = creator->name_space;
2013-06-19 12:13:45 +00:00
2024-08-11 23:54:29 +00:00
a->all_names_[0] = creator->name;
a->all_name_spaces_[0] = creator->name_space;
a->creator_ = creator;
a->context_ = p->h->context;
a->h_ = NULL;
a->next_ = NULL;
a->previous_ = NULL;
2024-08-11 23:54:29 +00:00
a->parent_ = p;
a->length_ = 0;
a->offset_ = 0;
a->flags_ = creator->flags;
a->set_ = creator->set;
2013-06-19 12:13:45 +00:00
2020-01-22 13:10:59 +00:00
if (p->block->last) {
2024-08-11 23:54:29 +00:00
a->offset_ = p->block->last->get_next_position_offset();
2023-06-24 11:28:28 +00:00
//printf("offset: p->block->last %s %s %ld %ld\n",
// p->block->last->cclass->name,
// p->block->last->name,(long)p->block->last->offset,(long)p->block->last->length);
2020-01-22 13:10:59 +00:00
}
else {
if (p->owner) {
2024-08-11 23:54:29 +00:00
a->offset_ = p->owner->offset_;
2020-01-22 13:10:59 +00:00
}
else
2024-08-11 23:54:29 +00:00
a->offset_ = 0;
2013-06-19 12:13:45 +00:00
}
a->init_accessor(len, params);
size = a->get_next_position_offset();
2013-06-19 12:13:45 +00:00
2020-01-22 13:10:59 +00:00
if (size > p->h->buffer->ulength) {
if (!p->h->buffer->growable) {
if (!p->h->partial)
2013-06-19 12:13:45 +00:00
grib_context_log(p->h->context, GRIB_LOG_ERROR,
"Creating (%s)%s of %s at offset %ld-%ld over message boundary (%lu)",
2024-08-11 23:54:29 +00:00
p->owner ? p->owner->name_ : "", a->name_,
creator->op, a->offset_,
a->offset_ + a->length_,
2020-01-22 13:10:59 +00:00
p->h->buffer->ulength);
2013-06-19 12:13:45 +00:00
a->destroy(p->h->context);
2013-06-19 12:13:45 +00:00
return NULL;
2020-01-22 13:10:59 +00:00
}
else {
grib_context_log(p->h->context, GRIB_LOG_DEBUG,
"CREATE: name=%s class=%s offset=%ld length=%ld action=",
2024-08-11 23:54:29 +00:00
a->name_, a->class_name_, a->offset_, a->length_);
2013-06-19 12:13:45 +00:00
2020-01-22 13:10:59 +00:00
grib_grow_buffer(p->h->context, p->h->buffer, size);
2013-06-19 12:13:45 +00:00
p->h->buffer->ulength = size;
}
}
if (p->h->context->debug == 1) {
2020-01-22 13:10:59 +00:00
if (p->owner)
grib_context_log(p->h->context, GRIB_LOG_DEBUG,
2020-01-22 13:10:59 +00:00
"Creating (%s)%s of %s at offset %d [len=%d]",
2024-08-11 23:54:29 +00:00
p->owner->name_, a->name_, creator->op, a->offset_, len, p->block);
else
grib_context_log(p->h->context, GRIB_LOG_DEBUG,
2020-01-22 13:10:59 +00:00
"Creating root %s of %s at offset %d [len=%d]",
2024-08-11 23:54:29 +00:00
a->name_, creator->op, a->offset_, len, p->block);
}
2013-06-19 12:13:45 +00:00
return a;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static void link_same_attributes(grib_accessor* a, grib_accessor* b)
2015-12-30 14:39:02 +00:00
{
2020-01-22 13:10:59 +00:00
int i = 0;
int idx = 0;
grib_accessor* bAttribute = NULL;
if (a == NULL || b == NULL)
return;
if (!b->has_attributes())
2020-01-22 13:10:59 +00:00
return;
2024-08-11 23:54:29 +00:00
while (i < MAX_ACCESSOR_ATTRIBUTES && a->attributes_[i]) {
bAttribute = b->get_attribute_index(a->attributes_[i]->name_, &idx);
2020-01-22 13:10:59 +00:00
if (bAttribute)
2024-08-11 23:54:29 +00:00
a->attributes_[i]->same_ = bAttribute;
2016-08-31 08:59:21 +00:00
i++;
}
2015-02-26 18:28:42 +00:00
}
2013-03-25 12:04:10 +00:00
void grib_push_accessor(grib_accessor* a, grib_block_of_accessors* l)
{
2013-06-19 12:13:45 +00:00
int id;
grib_handle* hand = grib_handle_of_accessor(a);
2013-06-19 12:13:45 +00:00
if (!l->first)
l->first = l->last = a;
2020-01-22 13:10:59 +00:00
else {
l->last->next_ = a;
a->previous_ = l->last;
2013-06-19 12:13:45 +00:00
}
l->last = a;
2013-03-25 12:04:10 +00:00
if (hand->use_trie) {
2024-08-11 23:54:29 +00:00
DEBUG_ASSERT( a->all_names_[0] );
if (*(a->all_names_[0]) != '_') {
id = grib_hash_keys_get_id(a->context_->keys, a->all_names_[0]);
2023-06-26 20:21:07 +00:00
DEBUG_ASSERT(id >= 0 && id < ACCESSORS_ARRAY_SIZE);
2024-08-11 23:54:29 +00:00
a->same_ = hand->accessors[id];
link_same_attributes(a, a->same_);
2020-01-22 13:10:59 +00:00
hand->accessors[id] = a;
2013-03-25 12:04:10 +00:00
2024-08-11 23:54:29 +00:00
if (a->same_ && (a->same_ == a)) {
fprintf(stderr, "---> %s\n", a->name_);
2024-12-20 12:58:07 +00:00
ECCODES_ASSERT(a->same_ != a);
2013-06-19 12:13:45 +00:00
}
}
2013-03-25 12:04:10 +00:00
}
}
void grib_section_post_init(grib_section* s)
{
2013-06-19 12:13:45 +00:00
grib_accessor* a = s ? s->block->first : NULL;
2020-01-22 13:10:59 +00:00
while (a) {
2024-08-11 23:54:29 +00:00
//grib_accessor_class* c = a->cclass;
//c->post_init(a);
a->post_init();
2024-08-11 23:54:29 +00:00
if (a->sub_section_)
grib_section_post_init(a->sub_section_);
a = a->next_;
2013-06-19 12:13:45 +00:00
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
int grib_section_adjust_sizes(grib_section* s, int update, int depth)
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
int err = 0;
2013-06-19 12:13:45 +00:00
grib_accessor* a = s ? s->block->first : NULL;
2020-01-22 13:10:59 +00:00
size_t length = update ? 0 : (s ? s->padding : 0);
2024-08-11 23:54:29 +00:00
size_t offset = (s && s->owner) ? s->owner->offset_ : 0;
2013-06-19 12:13:45 +00:00
int force_update = update > 1;
2020-01-22 13:10:59 +00:00
while (a) {
long l;
2013-06-19 12:13:45 +00:00
/* grib_section_adjust_sizes(grib_get_sub_section(a),update,depth+1); */
2024-08-11 23:54:29 +00:00
err = grib_section_adjust_sizes(a->sub_section_, update, depth + 1);
2020-01-22 13:10:59 +00:00
if (err)
return err;
/*grib_context_log(a->context,GRIB_LOG_DEBUG,"grib_section_adjust_sizes: %s %ld [len=%ld] (depth=%d)",a->name,(long)a->offset,(long)a->length,depth);*/
2013-06-19 12:13:45 +00:00
2024-08-11 23:54:29 +00:00
l = a->length_;
2013-06-19 12:13:45 +00:00
2024-08-11 23:54:29 +00:00
if (offset != a->offset_) {
grib_context_log(a->context_, GRIB_LOG_ERROR,
2022-11-18 17:09:11 +00:00
"Offset mismatch accessor=%s: accessor's offset=%ld, but actual offset=%ld",
2024-08-11 23:54:29 +00:00
a->name_, (long)a->offset_, (long)offset);
grib_context_log(a->context_, GRIB_LOG_ERROR, "Hint: Check section lengths are in sync with their contents");
a->offset_ = offset;
return GRIB_DECODING_ERROR;
2013-06-19 12:13:45 +00:00
}
length += l;
offset += l;
a = a->next_;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
if (s) {
if (s->aclength) {
size_t len = 1;
long plen = 0;
int lret = s->aclength->unpack_long(&plen, &len);
2024-12-20 12:58:07 +00:00
ECCODES_ASSERT(lret == GRIB_SUCCESS);
2013-06-19 12:13:45 +00:00
/* This happens when there is some padding */
2020-01-22 13:10:59 +00:00
if ((plen != length) || force_update) {
if (update) {
2013-06-19 12:13:45 +00:00
plen = length;
lret = s->aclength->pack_long(&plen, &len);
if (lret != GRIB_SUCCESS)
return lret;
2013-06-19 12:13:45 +00:00
s->padding = 0;
}
else {
2020-01-22 13:10:59 +00:00
if (!s->h->partial) {
if (length >= plen) {
2020-02-20 12:03:49 +00:00
if (s->owner) {
grib_context_log(s->h->context, GRIB_LOG_ERROR, "Invalid size %ld found for %s, assuming %ld",
2024-08-11 23:54:29 +00:00
(long)plen, s->owner->name_, (long)length);
2020-02-20 12:03:49 +00:00
}
2013-06-19 12:13:45 +00:00
plen = length;
}
s->padding = plen - length;
}
length = plen;
}
2013-03-25 12:04:10 +00:00
}
}
2020-01-22 13:10:59 +00:00
if (s->owner) {
/*grib_context_log(s->owner->context,GRIB_LOG_DEBUG,"grib_section_adjust_sizes: updating owner (%s->length old=%ld new=%ld)",s->owner->name,(long)s->owner->length,(long)length);*/
2024-08-11 23:54:29 +00:00
s->owner->length_ = length;
2015-06-08 14:12:30 +00:00
}
2013-06-19 12:13:45 +00:00
s->length = length;
}
return err;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
int grib_get_block_length(grib_section* s, size_t* l)
2013-03-25 12:04:10 +00:00
{
2013-06-19 12:13:45 +00:00
*l = s->length;
return GRIB_SUCCESS;
2023-08-23 21:19:07 +00:00
// TODO(masn): Because grib_pack_long takes a SIGNED value, we may have problems
2023-06-24 11:28:28 +00:00
// if(s->aclength) {
// size_t len = 1;
// long plen = 0;
// int ret = s->aclength->unpack_long(&plen, &len);
2023-06-24 11:28:28 +00:00
// if(ret == GRIB_SUCCESS && plen != 0)
// {
// *l = plen;
// return GRIB_SUCCESS;
// }
// }
// // empty block
// if(s->block->first == NULL) {
// *l = 0;
// return GRIB_SUCCESS;
// }
// // no accessor for block length
// if(s->owner) *l = s->block->last->get_next_position_offset() - s->owner->offset;
// else *l = s->block->last->get_next_position_offset();
2023-06-24 11:28:28 +00:00
// if(s->aclength) {
// size_t len = 1;
// long plen = *l;
// int ret = s->aclength->pack_long(&plen, &len);
2023-06-24 11:28:28 +00:00
// if(ret != GRIB_SUCCESS)
// ;
// if(s->h->context->debug)
// printf("SECTION updating length %ld %s\n",plen,s->owner->name);
// }
2024-12-20 12:58:07 +00:00
// // if(s->aclength) ECCODES_ASSERT(*l == plen);
2023-06-24 11:28:28 +00:00
// return GRIB_SUCCESS;
2013-03-25 12:04:10 +00:00
}
grib_accessor* find_paddings(grib_section* s)
{
2013-06-19 12:13:45 +00:00
grib_accessor* a = s ? s->block->first : NULL;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
while (a) {
2013-06-19 12:13:45 +00:00
/* grib_accessor* p = find_paddings(grib_get_sub_section(a)); */
2024-08-11 23:54:29 +00:00
grib_accessor* p = find_paddings(a->sub_section_);
2020-01-22 13:10:59 +00:00
if (p)
return p;
2013-03-25 12:04:10 +00:00
2024-08-11 23:54:29 +00:00
if (a->preferred_size(0) != a->length_)
2013-06-19 12:13:45 +00:00
return a;
2013-03-25 12:04:10 +00:00
a = a->next_;
2013-06-19 12:13:45 +00:00
}
2013-03-25 12:04:10 +00:00
2013-06-19 12:13:45 +00:00
return NULL;
2013-03-25 12:04:10 +00:00
}
void grib_update_paddings(grib_section* s)
{
2013-06-19 12:13:45 +00:00
grib_accessor* last = NULL;
grib_accessor* changed;
/* while((changed = find_paddings(s)) != NULL) */
2020-01-22 13:10:59 +00:00
while ((changed = find_paddings(s->h->root)) != NULL) {
2024-12-20 12:58:07 +00:00
ECCODES_ASSERT(changed != last);
changed->resize(changed->preferred_size(0));
2013-06-19 12:13:45 +00:00
last = changed;
}
2013-03-25 12:04:10 +00:00
}