mirror of https://github.com/ecmwf/eccodes.git
2078 lines
66 KiB
C++
2078 lines
66 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.
|
|
*/
|
|
/***************************************************************************
|
|
* Jean Baptiste Filippi - 01.11.2005
|
|
***************************************************************************/
|
|
|
|
#include "grib_api_internal.h"
|
|
#include "grib_value.h"
|
|
//#include "grib_accessor.h"
|
|
#include <float.h>
|
|
#include <limits>
|
|
#include <type_traits>
|
|
|
|
/* 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;
|
|
}
|
|
|
|
// Debug utility function to track GRIB packing/repacking issues
|
|
template <typename T>
|
|
static void print_debug_info__set_array(grib_handle* h, const char* func, const char* name, const T* val, size_t length)
|
|
{
|
|
size_t N = 7, i = 0;
|
|
T minVal = std::numeric_limits<T>::max();
|
|
T maxVal = -std::numeric_limits<T>::max();
|
|
double missingValue = 0;
|
|
ECCODES_ASSERT( h->context->debug );
|
|
|
|
if (grib_get_double(h, "missingValue", &missingValue)!=GRIB_SUCCESS) {
|
|
missingValue = 9999.0;
|
|
}
|
|
|
|
if (length <= N)
|
|
N = length;
|
|
fprintf(stderr, "ECCODES DEBUG %s h=%p key=%s, %zu entries (", func, (void*)h, name, length);
|
|
for (i = 0; i < N; ++i) {
|
|
if (i != 0) fprintf(stderr,", ");
|
|
fprintf(stderr, "%.10g", val[i]);
|
|
}
|
|
if (N >= length) fprintf(stderr, ") ");
|
|
else fprintf(stderr, "...) ");
|
|
for (i = 0; i < length; ++i) {
|
|
if (val[i] == (T)missingValue) continue;
|
|
if (val[i] < minVal) minVal = val[i];
|
|
if (val[i] > maxVal) maxVal = val[i];
|
|
}
|
|
fprintf(stderr, "min=%.10g, max=%.10g\n",minVal,maxVal);
|
|
}
|
|
|
|
static void print_error_no_accessor(const grib_context* c, const char* name)
|
|
{
|
|
grib_context_log(c, GRIB_LOG_ERROR, "Unable to find accessor %s", name);
|
|
const char* dpath = getenv("ECCODES_DEFINITION_PATH");
|
|
if (dpath != NULL) {
|
|
grib_context_log(c, GRIB_LOG_ERROR,
|
|
"Hint: This could be a symptom of an issue with your definitions.\n\t"
|
|
"The environment variable ECCODES_DEFINITION_PATH is defined and set to '%s'.\n\t"
|
|
"Please use the latest definitions.", dpath);
|
|
}
|
|
}
|
|
|
|
int grib_set_expression(grib_handle* h, const char* name, grib_expression* e)
|
|
{
|
|
grib_accessor* a = grib_find_accessor(h, name);
|
|
int ret = GRIB_SUCCESS;
|
|
|
|
if (a) {
|
|
if (a->flags_ & GRIB_ACCESSOR_FLAG_READ_ONLY)
|
|
return GRIB_READ_ONLY;
|
|
|
|
ret = a->pack_expression(e);
|
|
if (ret == GRIB_SUCCESS) {
|
|
return grib_dependency_notify_change(a);
|
|
}
|
|
return ret;
|
|
}
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
int grib_set_long_internal(grib_handle* h, const char* name, long val)
|
|
{
|
|
const grib_context* c = h->context;
|
|
int ret = GRIB_SUCCESS;
|
|
grib_accessor* a = NULL;
|
|
size_t l = 1;
|
|
|
|
a = grib_find_accessor(h, name);
|
|
|
|
if (h->context->debug)
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_long_internal h=%p %s=%ld\n", (void*)h, name, val);
|
|
|
|
if (a) {
|
|
ret = a->pack_long(&val, &l);
|
|
if (ret == GRIB_SUCCESS) {
|
|
return grib_dependency_notify_change(a);
|
|
}
|
|
|
|
grib_context_log(c, GRIB_LOG_ERROR, "Unable to set %s=%ld as long (%s)",
|
|
name, val, grib_get_error_message(ret));
|
|
return ret;
|
|
}
|
|
|
|
print_error_no_accessor(c, name);
|
|
//grib_context_log(c, GRIB_LOG_ERROR, "Unable to find accessor %s", name);
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
int grib_set_long(grib_handle* h, const char* name, long val)
|
|
{
|
|
int ret = GRIB_SUCCESS;
|
|
grib_accessor* a = NULL;
|
|
size_t l = 1;
|
|
|
|
a = grib_find_accessor(h, name);
|
|
|
|
if (a) {
|
|
if (h->context->debug) {
|
|
if (strcmp(name, a->name_)!=0)
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_long h=%p %s=%ld (a->name_=%s)\n", (void*)h, name, val, a->name_);
|
|
else
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_long h=%p %s=%ld\n", (void*)h, name, val);
|
|
}
|
|
|
|
if (a->flags_ & GRIB_ACCESSOR_FLAG_READ_ONLY)
|
|
return GRIB_READ_ONLY;
|
|
|
|
ret = a->pack_long(&val, &l);
|
|
if (ret == GRIB_SUCCESS)
|
|
return grib_dependency_notify_change(a);
|
|
|
|
return ret;
|
|
}
|
|
|
|
if (h->context->debug) {
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_long h=%p %s=%ld (Key not found)\n", (void*)h, name, val);
|
|
}
|
|
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
int grib_set_double_internal(grib_handle* h, const char* name, double val)
|
|
{
|
|
int ret = GRIB_SUCCESS;
|
|
grib_accessor* a = NULL;
|
|
size_t l = 1;
|
|
|
|
a = grib_find_accessor(h, name);
|
|
|
|
if (h->context->debug)
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_double_internal h=%p %s=%.10g\n", (void*)h, name, val);
|
|
|
|
if (a) {
|
|
ret = a->pack_double(&val, &l);
|
|
if (ret == GRIB_SUCCESS) {
|
|
return grib_dependency_notify_change(a);
|
|
}
|
|
|
|
grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to set %s=%g as double (%s)",
|
|
name, val, grib_get_error_message(ret));
|
|
return ret;
|
|
}
|
|
|
|
print_error_no_accessor(h->context, name);
|
|
//grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to find accessor %s", name);
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
typedef struct grib_key_err grib_key_err;
|
|
struct grib_key_err
|
|
{
|
|
char* name;
|
|
int err;
|
|
grib_key_err* next;
|
|
};
|
|
|
|
int grib_copy_namespace(grib_handle* dest, const char* name, grib_handle* src)
|
|
{
|
|
int* err = NULL;
|
|
int type, error_code = 0;
|
|
size_t len;
|
|
char* sval = NULL;
|
|
unsigned char* uval = NULL;
|
|
double* dval = NULL;
|
|
long* lval = NULL;
|
|
grib_key_err* key_err = NULL;
|
|
grib_key_err* first = NULL;
|
|
int todo = 1, count = 0;
|
|
|
|
grib_keys_iterator* iter = NULL;
|
|
|
|
if (!dest || !src)
|
|
return GRIB_NULL_HANDLE;
|
|
|
|
iter = grib_keys_iterator_new(src, 0, name);
|
|
|
|
if (!iter) {
|
|
grib_context_log(src->context, GRIB_LOG_ERROR, "grib_copy_namespace: Unable to get iterator for %s", name);
|
|
return GRIB_INTERNAL_ERROR;
|
|
}
|
|
|
|
while (grib_keys_iterator_next(iter)) {
|
|
grib_key_err* k = (grib_key_err*)grib_context_malloc_clear(src->context, sizeof(grib_key_err));
|
|
k->err = GRIB_NOT_FOUND;
|
|
k->name = grib_context_strdup(src->context, grib_keys_iterator_get_name(iter));
|
|
if (key_err == NULL) {
|
|
key_err = k;
|
|
first = k;
|
|
}
|
|
else {
|
|
key_err->next = k;
|
|
key_err = key_err->next;
|
|
}
|
|
}
|
|
|
|
count = 0;
|
|
todo = 1;
|
|
while (todo && count < 4) {
|
|
grib_accessor* a = NULL;
|
|
key_err = first;
|
|
while (key_err) {
|
|
const char* key = key_err->name;
|
|
err = &(key_err->err);
|
|
|
|
if (*err == GRIB_SUCCESS) {
|
|
key_err = key_err->next;
|
|
continue;
|
|
}
|
|
|
|
if ((a = grib_find_accessor(dest, key)) == NULL) {
|
|
key_err->err = GRIB_NOT_FOUND;
|
|
key_err = key_err->next;
|
|
continue;
|
|
}
|
|
|
|
if (a->flags_ & GRIB_ACCESSOR_FLAG_READ_ONLY) {
|
|
key_err->err = GRIB_SUCCESS;
|
|
key_err = key_err->next;
|
|
continue;
|
|
}
|
|
|
|
if (grib_is_missing(src, key, err) && *err == 0 && (*err = grib_set_missing(dest, key))) {
|
|
if (*err != GRIB_SUCCESS && *err != GRIB_NOT_FOUND)
|
|
return *err;
|
|
key_err = key_err->next;
|
|
continue;
|
|
}
|
|
|
|
if ((*err = grib_get_native_type(dest, key, &type)) != GRIB_SUCCESS) {
|
|
if (*err != GRIB_SUCCESS && *err != GRIB_NOT_FOUND)
|
|
return *err;
|
|
key_err = key_err->next;
|
|
continue;
|
|
}
|
|
|
|
if ((*err = grib_get_size(src, key, &len)) != GRIB_SUCCESS)
|
|
return *err;
|
|
|
|
switch (type) {
|
|
case GRIB_TYPE_STRING:
|
|
len = 1024;
|
|
sval = (char*)grib_context_malloc(src->context, len * sizeof(char));
|
|
|
|
if ((*err = grib_get_string(src, key, sval, &len)) != GRIB_SUCCESS)
|
|
return *err;
|
|
|
|
if ((*err = grib_set_string(dest, key, sval, &len)) != GRIB_SUCCESS)
|
|
return *err;
|
|
|
|
grib_context_free(src->context, sval);
|
|
break;
|
|
|
|
case GRIB_TYPE_LONG:
|
|
lval = (long*)grib_context_malloc(src->context, len * sizeof(long));
|
|
|
|
if ((*err = grib_get_long_array(src, key, lval, &len)) != GRIB_SUCCESS)
|
|
return *err;
|
|
|
|
if ((*err = grib_set_long_array(dest, key, lval, len)) != GRIB_SUCCESS)
|
|
return *err;
|
|
|
|
grib_context_free(src->context, lval);
|
|
break;
|
|
|
|
case GRIB_TYPE_DOUBLE:
|
|
dval = (double*)grib_context_malloc(src->context, len * sizeof(double));
|
|
|
|
if ((*err = grib_get_double_array(src, key, dval, &len)) != GRIB_SUCCESS)
|
|
return *err;
|
|
|
|
if ((*err = grib_set_double_array(dest, key, dval, len)) != GRIB_SUCCESS)
|
|
return *err;
|
|
|
|
grib_context_free(src->context, dval);
|
|
break;
|
|
|
|
case GRIB_TYPE_BYTES:
|
|
len = 1024;
|
|
uval = (unsigned char*)grib_context_malloc(src->context, len * sizeof(unsigned char));
|
|
|
|
if ((*err = grib_get_bytes(src, key, uval, &len)) != GRIB_SUCCESS)
|
|
return *err;
|
|
|
|
if ((*err = grib_get_bytes(dest, key, uval, &len)) != GRIB_SUCCESS)
|
|
return *err;
|
|
|
|
grib_context_free(src->context, uval);
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
key_err = key_err->next;
|
|
}
|
|
count++;
|
|
key_err = first;
|
|
todo = 0;
|
|
while (key_err) {
|
|
if (key_err->err == GRIB_NOT_FOUND) {
|
|
todo = 1;
|
|
break;
|
|
}
|
|
key_err = key_err->next;
|
|
}
|
|
}
|
|
if (err)
|
|
error_code = *err; // copy the error code before cleanup
|
|
grib_keys_iterator_delete(iter);
|
|
key_err = first;
|
|
while (key_err) {
|
|
grib_key_err* next = key_err->next;
|
|
grib_context_free(src->context, key_err->name);
|
|
grib_context_free(src->context, key_err);
|
|
key_err = next;
|
|
}
|
|
|
|
return error_code;
|
|
}
|
|
|
|
int grib_set_double(grib_handle* h, const char* name, double val)
|
|
{
|
|
int ret = GRIB_SUCCESS;
|
|
grib_accessor* a = NULL;
|
|
size_t l = 1;
|
|
|
|
a = grib_find_accessor(h, name);
|
|
|
|
if (a) {
|
|
if (h->context->debug) {
|
|
if (strcmp(name, a->name_)!=0)
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_double h=%p %s=%.10g (a->name_=%s)\n", (void*)h, name, val, a->name_);
|
|
else
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_double h=%p %s=%.10g\n", (void*)h, name, val);
|
|
}
|
|
|
|
if (a->flags_ & GRIB_ACCESSOR_FLAG_READ_ONLY)
|
|
return GRIB_READ_ONLY;
|
|
|
|
ret = a->pack_double(&val, &l);
|
|
if (ret == GRIB_SUCCESS)
|
|
return grib_dependency_notify_change(a);
|
|
|
|
return ret;
|
|
}
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
int grib_set_string_internal(grib_handle* h, const char* name,
|
|
const char* val, size_t* length)
|
|
{
|
|
int ret = GRIB_SUCCESS;
|
|
grib_accessor* a = NULL;
|
|
|
|
a = grib_find_accessor(h, name);
|
|
|
|
if (h->context->debug)
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_string_internal h=%p %s=%s\n", (void*)h, name, val);
|
|
|
|
if (a) {
|
|
ret = a->pack_string(val, length);
|
|
if (ret == GRIB_SUCCESS) {
|
|
return grib_dependency_notify_change(a);
|
|
}
|
|
|
|
grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to set %s=%s as string (%s)",
|
|
name, val, grib_get_error_message(ret));
|
|
return ret;
|
|
}
|
|
|
|
print_error_no_accessor(h->context, name);
|
|
//grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to find accessor %s", name);
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
// Return 1 if we dealt with specific packing type changes and nothing more needs doing.
|
|
// Return 0 if further action is needed
|
|
static int preprocess_packingType_change(grib_handle* h, const char* keyname, const char* keyval)
|
|
{
|
|
int err = 0;
|
|
char input_packing_type[100] = {0,};
|
|
size_t len = sizeof(input_packing_type);
|
|
|
|
if (grib_inline_strcmp(keyname, "packingType") == 0) {
|
|
/* Second order doesn't have a proper representation for constant fields.
|
|
So best not to do the change of packing type.
|
|
Use strncmp to catch all flavours of 2nd order packing e.g. grid_second_order_boustrophedonic */
|
|
if (strncmp(keyval, "grid_second_order", 17) == 0) {
|
|
long bitsPerValue = 0;
|
|
size_t numCodedVals = 0;
|
|
err = grib_get_long(h, "bitsPerValue", &bitsPerValue);
|
|
if (!err && bitsPerValue == 0) {
|
|
/* ECC-1219: packingType conversion from grid_ieee to grid_second_order.
|
|
* Normally having a bitsPerValue of 0 means a constant field but this is
|
|
* not so for IEEE packing which can be non-constant but always has bitsPerValue==0! */
|
|
len = sizeof(input_packing_type);
|
|
grib_get_string(h, "packingType", input_packing_type, &len);
|
|
if (strcmp(input_packing_type, "grid_ieee") != 0) {
|
|
/* Not IEEE, so bitsPerValue==0 really means constant field */
|
|
if (h->context->debug) {
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_string packingType: "
|
|
"Constant field cannot be encoded in second order. Packing not changed\n");
|
|
}
|
|
return 1; /* Dealt with - no further action needed */
|
|
}
|
|
}
|
|
/* GRIB-883: check if there are enough coded values */
|
|
err = grib_get_size(h, "codedValues", &numCodedVals);
|
|
if (!err && numCodedVals < 3) {
|
|
if (h->context->debug) {
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_string packingType: "
|
|
"Not enough coded values for second order. Packing not changed\n");
|
|
}
|
|
return 1; /* Dealt with - no further action needed */
|
|
}
|
|
}
|
|
|
|
/* ECC-1407: Are we changing from IEEE to CCSDS or Simple? */
|
|
if (strcmp(keyval, "grid_simple")==0 || strcmp(keyval, "grid_ccsds")==0) {
|
|
grib_get_string(h, "packingType", input_packing_type, &len);
|
|
if (strcmp(input_packing_type, "grid_ieee") == 0) {
|
|
const long max_bpv = 32; /* Cannot do any higher */
|
|
grib_set_long(h, "bitsPerValue", max_bpv);
|
|
//long accuracy = 0;
|
|
//err = grib_get_long(h, "accuracy", &accuracy);
|
|
//if (!err) grib_set_long(h, "bitsPerValue", accuracy);
|
|
}
|
|
}
|
|
}
|
|
return 0; /* Further action is needed */
|
|
}
|
|
|
|
static void postprocess_packingType_change(grib_handle* h, const char* keyname, const char* keyval)
|
|
{
|
|
if (grib_inline_strcmp(keyname, "packingType") == 0) {
|
|
long is_experimental = 0, is_deprecated = 0;
|
|
if (grib_get_long(h, "isTemplateExperimental", &is_experimental) == GRIB_SUCCESS && is_experimental == 1) {
|
|
fprintf(stderr, "ECCODES WARNING : The template for %s=%s is experimental. "
|
|
"This template was not validated at the time of publication.\n",
|
|
keyname, keyval);
|
|
return;
|
|
}
|
|
if (grib_get_long(h, "isTemplateDeprecated", &is_deprecated) == GRIB_SUCCESS && is_deprecated == 1) {
|
|
fprintf(stderr, "ECCODES WARNING : The template for %s=%s is deprecated.\n", keyname, keyval);
|
|
}
|
|
}
|
|
}
|
|
|
|
int grib_set_string(grib_handle* h, const char* name, const char* val, size_t* length)
|
|
{
|
|
int ret = 0;
|
|
grib_accessor* a = NULL;
|
|
|
|
int processed = preprocess_packingType_change(h, name, val);
|
|
if (processed)
|
|
return GRIB_SUCCESS; // Dealt with - no further action needed
|
|
|
|
a = grib_find_accessor(h, name);
|
|
|
|
if (a) {
|
|
if (h->context->debug) {
|
|
if (strcmp(name, a->name_)!=0)
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_string h=%p %s=|%s| (a->name_=%s)\n", (void*)h, name, val, a->name_);
|
|
else
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_string h=%p %s=|%s|\n", (void*)h, name, val);
|
|
}
|
|
|
|
if (a->flags_ & GRIB_ACCESSOR_FLAG_READ_ONLY)
|
|
return GRIB_READ_ONLY;
|
|
|
|
ret = a->pack_string(val, length);
|
|
if (ret == GRIB_SUCCESS) {
|
|
postprocess_packingType_change(h, name, val);
|
|
return grib_dependency_notify_change(a);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
if (h->context->debug) {
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_string %s=|%s| (Key not found)\n", name, val);
|
|
}
|
|
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
int grib_set_string_array(grib_handle* h, const char* name, const char** val, size_t length)
|
|
{
|
|
int ret = 0;
|
|
grib_accessor* a;
|
|
|
|
a = grib_find_accessor(h, name);
|
|
|
|
if (h->context->debug) {
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_string_array h=%p key=%s %zu values\n", (void*)h, name, length);
|
|
}
|
|
|
|
if (a) {
|
|
if (a->flags_ & GRIB_ACCESSOR_FLAG_READ_ONLY)
|
|
return GRIB_READ_ONLY;
|
|
|
|
ret = a->pack_string_array(val, &length);
|
|
if (ret == GRIB_SUCCESS) {
|
|
return grib_dependency_notify_change(a);
|
|
}
|
|
return ret;
|
|
}
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
// int grib_set_bytes_internal(grib_handle* h, const char* name, const unsigned char* val, size_t* length)
|
|
// {
|
|
// int ret = GRIB_SUCCESS;
|
|
// grib_accessor* a = NULL;
|
|
// a = grib_find_accessor(h, name);
|
|
// if (a) {
|
|
// ret = a->pack_bytes(val, length);
|
|
// if (ret == GRIB_SUCCESS) {
|
|
// return grib_dependency_notify_change(a);
|
|
// }
|
|
// grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to set %s=%s as bytes (%s)",
|
|
// name, val, grib_get_error_message(ret));
|
|
// return ret;
|
|
// }
|
|
// grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to find accessor %s", name);
|
|
// return GRIB_NOT_FOUND;
|
|
// }
|
|
|
|
int grib_set_bytes(grib_handle* h, const char* name, const unsigned char* val, size_t* length)
|
|
{
|
|
int ret = 0;
|
|
grib_accessor* a = grib_find_accessor(h, name);
|
|
|
|
if (a) {
|
|
// if(a->flags_ & GRIB_ACCESSOR_FLAG_READ_ONLY)
|
|
// return GRIB_READ_ONLY;
|
|
|
|
ret = a->pack_bytes(val, length);
|
|
if (ret == GRIB_SUCCESS) {
|
|
return grib_dependency_notify_change(a);
|
|
}
|
|
return ret;
|
|
}
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
// int grib_clear(grib_handle* h, const char* name)
|
|
// {
|
|
// int ret = 0;
|
|
// grib_accessor* a = NULL;
|
|
// a = grib_find_accessor(h, name);
|
|
// if (a) {
|
|
// if (a->length_ == 0)
|
|
// return 0;
|
|
// if ((ret = a->grib_pack_zero()) != GRIB_SUCCESS)
|
|
// grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to clear %s (%s)",
|
|
// name, grib_get_error_message(ret));
|
|
// return ret;
|
|
// }
|
|
// /*grib_context_log(h->context,GRIB_LOG_ERROR,"Unable to find accessor %s",name);*/
|
|
// return GRIB_NOT_FOUND;
|
|
// }
|
|
|
|
int grib_set_missing(grib_handle* h, const char* name)
|
|
{
|
|
int ret = 0;
|
|
grib_accessor* a = NULL;
|
|
|
|
a = grib_find_accessor(h, name);
|
|
|
|
if (a) {
|
|
if (a->flags_ & GRIB_ACCESSOR_FLAG_READ_ONLY)
|
|
return GRIB_READ_ONLY;
|
|
|
|
if (grib_accessor_can_be_missing(a, &ret)) {
|
|
if (h->context->debug)
|
|
fprintf(stderr, "ECCODES DEBUG grib_set_missing h=%p %s\n", (void*)h, name);
|
|
|
|
ret = a->pack_missing();
|
|
if (ret == GRIB_SUCCESS)
|
|
return grib_dependency_notify_change(a);
|
|
}
|
|
else
|
|
ret = GRIB_VALUE_CANNOT_BE_MISSING;
|
|
|
|
grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to set %s=missing (%s)",
|
|
name, grib_get_error_message(ret));
|
|
return ret;
|
|
}
|
|
|
|
grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to find accessor %s", name);
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
int grib_is_missing_long(grib_accessor* a, long x)
|
|
{
|
|
int ret = (a == NULL || (a->flags_ & GRIB_ACCESSOR_FLAG_CAN_BE_MISSING)) && (x == GRIB_MISSING_LONG) ? 1 : 0;
|
|
return ret;
|
|
}
|
|
int grib_is_missing_double(grib_accessor* a, double x)
|
|
{
|
|
int ret = (a == NULL || (a->flags_ & GRIB_ACCESSOR_FLAG_CAN_BE_MISSING)) && (x == GRIB_MISSING_DOUBLE) ? 1 : 0;
|
|
return ret;
|
|
}
|
|
|
|
int grib_is_missing_string(grib_accessor* a, const unsigned char* x, size_t len)
|
|
{
|
|
// For a string value to be missing, every character has to be */
|
|
// all 1's (i.e. 0xFF) */
|
|
// Note: An empty string is also classified as missing */
|
|
int ret;
|
|
size_t i = 0;
|
|
|
|
if (len == 0)
|
|
return 1; // empty string
|
|
ret = 1;
|
|
for (i = 0; i < len; i++) {
|
|
if (x[i] != 0xFF) {
|
|
ret = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!a) return ret;
|
|
|
|
ret = ( ((a->flags_ & GRIB_ACCESSOR_FLAG_CAN_BE_MISSING) && ret == 1) ) ? 1 : 0;
|
|
return ret;
|
|
}
|
|
|
|
int grib_accessor_is_missing(grib_accessor* a, int* err)
|
|
{
|
|
*err = GRIB_SUCCESS;
|
|
if (a) {
|
|
if (a->flags_ & GRIB_ACCESSOR_FLAG_CAN_BE_MISSING)
|
|
return a->is_missing_internal();
|
|
else
|
|
return 0;
|
|
}
|
|
else {
|
|
*err = GRIB_NOT_FOUND;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int grib_accessor_can_be_missing(grib_accessor* a, int* err)
|
|
{
|
|
if (a->flags_ & GRIB_ACCESSOR_FLAG_CAN_BE_MISSING) {
|
|
return 1;
|
|
}
|
|
if (STR_EQUAL(a->class_name_, "codetable")) {
|
|
// Special case of Code Table keys
|
|
// The vast majority have a 'Missing' entry
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int grib_is_missing(const grib_handle* h, const char* name, int* err)
|
|
{
|
|
grib_accessor* a = grib_find_accessor(h, name);
|
|
return grib_accessor_is_missing(a, err);
|
|
}
|
|
|
|
// Return true if the given key exists (is defined) in our grib message
|
|
int grib_is_defined(const grib_handle* h, const char* name)
|
|
{
|
|
const grib_accessor* a = grib_find_accessor(h, name);
|
|
return (a ? 1 : 0);
|
|
}
|
|
|
|
int grib_set_flag(grib_handle* h, const char* name, unsigned long flag)
|
|
{
|
|
grib_accessor* a = grib_find_accessor(h, name);
|
|
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
|
|
a->flags_ |= flag;
|
|
|
|
return GRIB_SUCCESS;
|
|
}
|
|
|
|
static int _grib_set_double_array_internal(grib_handle* h, grib_accessor* a,
|
|
const double* val, size_t buffer_len, size_t* encoded_length, int check)
|
|
{
|
|
if (a) {
|
|
int err = _grib_set_double_array_internal(h, a->same_, val, buffer_len, encoded_length, check);
|
|
|
|
if (check && (a->flags_ & GRIB_ACCESSOR_FLAG_READ_ONLY))
|
|
return GRIB_READ_ONLY;
|
|
|
|
if (err == GRIB_SUCCESS) {
|
|
size_t len = buffer_len - *encoded_length;
|
|
if (len) {
|
|
err = a->pack_double(val + *encoded_length, &len);
|
|
*encoded_length += len;
|
|
if (err == GRIB_SUCCESS) {
|
|
// See ECC-778
|
|
return grib_dependency_notify_change_h(h, a);
|
|
}
|
|
}
|
|
else {
|
|
grib_get_size(h, a->name_, encoded_length);
|
|
err = GRIB_WRONG_ARRAY_SIZE;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
else {
|
|
return GRIB_SUCCESS;
|
|
}
|
|
}
|
|
|
|
static int _grib_set_double_array(grib_handle* h, const char* name,
|
|
const double* val, size_t length, int check)
|
|
{
|
|
size_t encoded = 0;
|
|
grib_accessor* a = grib_find_accessor(h, name);
|
|
int err = 0;
|
|
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
if (name[0] == '/' || name[0] == '#') {
|
|
if (check && (a->flags_ & GRIB_ACCESSOR_FLAG_READ_ONLY))
|
|
return GRIB_READ_ONLY;
|
|
err = a->pack_double(val, &length);
|
|
encoded = length;
|
|
}
|
|
else
|
|
err = _grib_set_double_array_internal(h, a, val, length, &encoded, check);
|
|
|
|
if (err == GRIB_SUCCESS && length > encoded)
|
|
err = GRIB_ARRAY_TOO_SMALL;
|
|
|
|
if (err == GRIB_SUCCESS)
|
|
return grib_dependency_notify_change_h(h, a); // See ECC-778
|
|
|
|
return err;
|
|
}
|
|
|
|
int grib_set_double_array_internal(grib_handle* h, const char* name, const double* val, size_t length)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (h->context->debug) {
|
|
print_debug_info__set_array(h, __func__, name, val, length);
|
|
}
|
|
|
|
if (length == 0) {
|
|
grib_accessor* a = grib_find_accessor(h, name);
|
|
ret = a->pack_double(val, &length);
|
|
}
|
|
else {
|
|
ret = _grib_set_double_array(h, name, val, length, 0);
|
|
}
|
|
|
|
if (ret != GRIB_SUCCESS)
|
|
grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to set double array '%s' (%s)",
|
|
name, grib_get_error_message(ret));
|
|
//if (h->context->debug) fprintf(stderr,"ECCODES DEBUG grib_set_double_array_internal key=%s --DONE\n",name);
|
|
return ret;
|
|
}
|
|
|
|
int grib_set_float_array_internal(grib_handle* h, const char* name, const float* val, size_t length)
|
|
{
|
|
return GRIB_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static int __grib_set_double_array(grib_handle* h, const char* name, const double* val, size_t length, int check)
|
|
{
|
|
double v = 0;
|
|
size_t i = 0;
|
|
|
|
if (h->context->debug) {
|
|
print_debug_info__set_array(h, __func__, name, val, length);
|
|
}
|
|
|
|
if (length == 0) {
|
|
grib_accessor* a = grib_find_accessor(h, name);
|
|
return a->pack_double(val, &length);
|
|
}
|
|
|
|
/*second order doesn't have a proper representation for constant fields
|
|
the best is not to do the change of packing type if the field is constant
|
|
*/
|
|
if (!strcmp(name, "values") || !strcmp(name, "codedValues")) {
|
|
double missingValue;
|
|
int ret = 0;
|
|
int constant = 0;
|
|
|
|
ret = grib_get_double(h, "missingValue", &missingValue);
|
|
if (ret)
|
|
missingValue = 9999;
|
|
|
|
v = missingValue;
|
|
constant = 1;
|
|
for (i = 0; i < length; i++) {
|
|
if (val[i] != missingValue) {
|
|
if (v == missingValue) {
|
|
v = val[i];
|
|
}
|
|
else if (v != val[i]) {
|
|
constant = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (constant) {
|
|
char packingType[50] = {0,};
|
|
size_t slen = 50;
|
|
|
|
grib_get_string(h, "packingType", packingType, &slen);
|
|
if (!strcmp(packingType, "grid_second_order") ||
|
|
!strcmp(packingType, "grid_second_order_no_SPD") ||
|
|
!strcmp(packingType, "grid_second_order_SPD1") ||
|
|
!strcmp(packingType, "grid_second_order_SPD2") ||
|
|
!strcmp(packingType, "grid_second_order_SPD3")) {
|
|
slen = 11; /*length of 'grid_simple' */
|
|
if (h->context->debug) {
|
|
fprintf(stderr, "ECCODES DEBUG __grib_set_double_array: Cannot use second order packing for constant fields. Using simple packing\n");
|
|
}
|
|
ret = grib_set_string(h, "packingType", "grid_simple", &slen);
|
|
if (ret != GRIB_SUCCESS) {
|
|
if (h->context->debug) {
|
|
fprintf(stderr, "ECCODES DEBUG __grib_set_double_array: could not switch to simple packing!\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return _grib_set_double_array(h, name, val, length, check);
|
|
}
|
|
|
|
int grib_set_force_double_array(grib_handle* h, const char* name, const double* val, size_t length)
|
|
{
|
|
/* GRIB-285: Same as grib_set_double_array but allows setting of READ-ONLY keys like codedValues */
|
|
/* Use with great caution!! */
|
|
return __grib_set_double_array(h, name, val, length, /*check=*/0);
|
|
}
|
|
int grib_set_force_float_array(grib_handle* h, const char* name, const float* val, size_t length)
|
|
{
|
|
/* GRIB-285: Same as grib_set_float_array but allows setting of READ-ONLY keys like codedValues */
|
|
/* Use with great caution!! */
|
|
//return __grib_set_float_array(h, name, val, length, /*check=*/0);
|
|
return GRIB_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
int grib_set_double_array(grib_handle* h, const char* name, const double* val, size_t length)
|
|
{
|
|
return __grib_set_double_array(h, name, val, length, /*check=*/1);
|
|
}
|
|
int grib_set_float_array(grib_handle* h, const char* name, const float* val, size_t length)
|
|
{
|
|
//return __grib_set_float_array(h, name, val, length, /*check=*/1);
|
|
return GRIB_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
static int _grib_set_long_array_internal(grib_handle* h, grib_accessor* a, const long* val, size_t buffer_len, size_t* encoded_length, int check)
|
|
{
|
|
if (a) {
|
|
int err = _grib_set_long_array_internal(h, a->same_, val, buffer_len, encoded_length, check);
|
|
|
|
if (check && (a->flags_ & GRIB_ACCESSOR_FLAG_READ_ONLY))
|
|
return GRIB_READ_ONLY;
|
|
|
|
if (err == GRIB_SUCCESS) {
|
|
size_t len = buffer_len - *encoded_length;
|
|
if (len) {
|
|
err = a->pack_long(val + *encoded_length, &len);
|
|
*encoded_length += len;
|
|
}
|
|
else {
|
|
grib_get_size(h, a->name_, encoded_length);
|
|
err = GRIB_WRONG_ARRAY_SIZE;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
else {
|
|
return GRIB_SUCCESS;
|
|
}
|
|
}
|
|
|
|
static int _grib_set_long_array(grib_handle* h, const char* name, const long* val, size_t length, int check)
|
|
{
|
|
size_t encoded = 0;
|
|
grib_accessor* a = grib_find_accessor(h, name);
|
|
int err = 0;
|
|
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
|
|
if (h->context->debug) {
|
|
size_t i = 0;
|
|
size_t N = 5;
|
|
if (length <= N)
|
|
N = length;
|
|
fprintf(stderr, "ECCODES DEBUG _grib_set_long_array h=%p key=%s %zu values (", (void*)h, name, length);
|
|
for (i = 0; i < N; ++i)
|
|
fprintf(stderr, " %ld,", val[i]);
|
|
if (N >= length)
|
|
fprintf(stderr, " )\n");
|
|
else
|
|
fprintf(stderr, " ... )\n");
|
|
}
|
|
|
|
if (name[0] == '/' || name[0] == '#') {
|
|
if (check && (a->flags_ & GRIB_ACCESSOR_FLAG_READ_ONLY))
|
|
return GRIB_READ_ONLY;
|
|
err = a->pack_long(val, &length);
|
|
encoded = length;
|
|
}
|
|
else
|
|
err = _grib_set_long_array_internal(h, a, val, length, &encoded, check);
|
|
|
|
if (err == GRIB_SUCCESS && length > encoded)
|
|
err = GRIB_ARRAY_TOO_SMALL;
|
|
|
|
if (err == GRIB_SUCCESS)
|
|
return grib_dependency_notify_change(a);
|
|
|
|
return err;
|
|
}
|
|
|
|
int grib_set_long_array_internal(grib_handle* h, const char* name, const long* val, size_t length)
|
|
{
|
|
int ret = _grib_set_long_array(h, name, val, length, 0);
|
|
if (ret != GRIB_SUCCESS)
|
|
grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to set long array '%s' (%s)",
|
|
name, grib_get_error_message(ret));
|
|
return ret;
|
|
}
|
|
|
|
int grib_set_long_array(grib_handle* h, const char* name, const long* val, size_t length)
|
|
{
|
|
return _grib_set_long_array(h, name, val, length, 1);
|
|
}
|
|
|
|
int grib_get_long_internal(grib_handle* h, const char* name, long* val)
|
|
{
|
|
int ret = grib_get_long(h, name, val);
|
|
|
|
if (ret != GRIB_SUCCESS) {
|
|
grib_context_log(h->context, GRIB_LOG_ERROR,
|
|
"Unable to get %s as long (%s)",
|
|
name, grib_get_error_message(ret));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// int grib_is_in_dump(const grib_handle* h, const char* name)
|
|
// {
|
|
// const grib_accessor* a = grib_find_accessor(h, name);
|
|
// if (a != NULL && (a->flags_ & GRIB_ACCESSOR_FLAG_DUMP))
|
|
// return 1;
|
|
// else
|
|
// return 0;
|
|
// }
|
|
|
|
// int grib_attributes_count(const grib_accessor* a, size_t* size)
|
|
// {
|
|
// if (a) {
|
|
// *size = 0;
|
|
// while (a->attributes_[*size] != NULL) {
|
|
// (*size)++;
|
|
// }
|
|
// return GRIB_SUCCESS;
|
|
// }
|
|
// return GRIB_NOT_FOUND;
|
|
// }
|
|
|
|
int grib_get_long(const grib_handle* h, const char* name, long* val)
|
|
{
|
|
size_t length = 1;
|
|
grib_accessor* a = NULL;
|
|
grib_accessors_list* al = NULL;
|
|
int ret = 0;
|
|
|
|
if (name[0] == '/') {
|
|
al = grib_find_accessors_list(h, name);
|
|
if (!al)
|
|
return GRIB_NOT_FOUND;
|
|
ret = al->accessor->unpack_long(val, &length);
|
|
grib_context_free(h->context, al);
|
|
}
|
|
else {
|
|
a = grib_find_accessor(h, name);
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
ret = a->unpack_long(val, &length);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int grib_get_double_internal(grib_handle* h, const char* name, double* val)
|
|
{
|
|
int ret = grib_get_double(h, name, val);
|
|
|
|
if (ret != GRIB_SUCCESS)
|
|
grib_context_log(h->context, GRIB_LOG_ERROR,
|
|
"Unable to get %s as double (%s)",
|
|
name, grib_get_error_message(ret));
|
|
|
|
return ret;
|
|
}
|
|
|
|
int grib_get_double(const grib_handle* h, const char* name, double* val)
|
|
{
|
|
size_t length = 1;
|
|
grib_accessor* a = NULL;
|
|
grib_accessors_list* al = NULL;
|
|
int ret = 0;
|
|
|
|
if (name[0] == '/') {
|
|
al = grib_find_accessors_list(h, name);
|
|
if (!al)
|
|
return GRIB_NOT_FOUND;
|
|
ret = al->accessor->unpack_double(val, &length);
|
|
grib_context_free(h->context, al);
|
|
}
|
|
else {
|
|
a = grib_find_accessor(h, name);
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
ret = a->unpack_double(val, &length);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int grib_get_float(const grib_handle* h, const char* name, float* val)
|
|
{
|
|
size_t length = 1;
|
|
grib_accessor* a = NULL;
|
|
grib_accessors_list* al = NULL;
|
|
int ret = 0;
|
|
|
|
if (name[0] == '/') {
|
|
al = grib_find_accessors_list(h, name);
|
|
if (!al)
|
|
return GRIB_NOT_FOUND;
|
|
ret = al->accessor->unpack_float(val, &length);
|
|
grib_context_free(h->context, al);
|
|
}
|
|
else {
|
|
a = grib_find_accessor(h, name);
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
ret = a->unpack_float(val, &length);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int grib_get_double_element_internal(grib_handle* h, const char* name, int i, double* val)
|
|
{
|
|
int ret = grib_get_double_element(h, name, i, val);
|
|
|
|
if (ret != GRIB_SUCCESS)
|
|
grib_context_log(h->context, GRIB_LOG_ERROR,
|
|
"Unable to get %s as double element (%s)",
|
|
name, grib_get_error_message(ret));
|
|
|
|
return ret;
|
|
}
|
|
|
|
int grib_get_double_element(const grib_handle* h, const char* name, int i, double* val)
|
|
{
|
|
grib_accessor* act = grib_find_accessor(h, name);
|
|
|
|
if (act) {
|
|
return act->unpack_double_element(i, val);
|
|
}
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
int grib_get_float_element(const grib_handle* h, const char* name, int i, float* val)
|
|
{
|
|
grib_accessor* act = grib_find_accessor(h, name);
|
|
|
|
if (act) {
|
|
return act->unpack_float_element(i, val);
|
|
}
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
int grib_get_double_element_set_internal(grib_handle* h, const char* name, const size_t* index_array, size_t len, double* val_array)
|
|
{
|
|
int ret = grib_get_double_element_set(h, name, index_array, len, val_array);
|
|
|
|
if (ret != GRIB_SUCCESS)
|
|
grib_context_log(h->context, GRIB_LOG_ERROR,
|
|
"Unable to get %s as double element set (%s)",
|
|
name, grib_get_error_message(ret));
|
|
|
|
return ret;
|
|
}
|
|
int grib_get_float_element_set_internal(grib_handle* h, const char* name, const size_t* index_array, size_t len, float* val_array)
|
|
{
|
|
int ret = grib_get_float_element_set(h, name, index_array, len, val_array);
|
|
|
|
if (ret != GRIB_SUCCESS)
|
|
grib_context_log(h->context, GRIB_LOG_ERROR,
|
|
"Unable to get %s as float element set (%s)",
|
|
name, grib_get_error_message(ret));
|
|
|
|
return ret;
|
|
}
|
|
|
|
int grib_get_double_element_set(const grib_handle* h, const char* name, const size_t* index_array, size_t len, double* val_array)
|
|
{
|
|
grib_accessor* acc = grib_find_accessor(h, name);
|
|
|
|
if (acc) {
|
|
return acc->unpack_double_element_set(index_array, len, val_array);
|
|
}
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
int grib_get_float_element_set(const grib_handle* h, const char* name, const size_t* index_array, size_t len, float* val_array)
|
|
{
|
|
grib_accessor* acc = grib_find_accessor(h, name);
|
|
|
|
if (acc) {
|
|
return acc->unpack_float_element_set(index_array, len, val_array);
|
|
}
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
int grib_get_double_elements(const grib_handle* h, const char* name, const int* index_array, long len, double* val_array)
|
|
{
|
|
double* values = 0;
|
|
int err = 0;
|
|
size_t size = 0, num_bytes = 0;
|
|
long j = 0;
|
|
grib_accessor* act = NULL;
|
|
|
|
act = grib_find_accessor(h, name);
|
|
if (!act)
|
|
return GRIB_NOT_FOUND;
|
|
|
|
err = grib_get_size_acc(h, act, &size);
|
|
|
|
if (err != GRIB_SUCCESS) {
|
|
grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Cannot get size of %s", __func__, name);
|
|
return err;
|
|
}
|
|
|
|
/* Check index array has valid values */
|
|
for (j = 0; j < len; j++) {
|
|
const int anIndex = index_array[j];
|
|
if (anIndex < 0 || anIndex >= size) {
|
|
grib_context_log(h->context, GRIB_LOG_ERROR,
|
|
"%s: Index out of range: %d (should be between 0 and %zu)", __func__, anIndex, size - 1);
|
|
return GRIB_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
|
|
num_bytes = size * sizeof(double);
|
|
values = (double*)grib_context_malloc(h->context, num_bytes);
|
|
if (!values) {
|
|
grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Unable to allocate %zu bytes", __func__, num_bytes);
|
|
return GRIB_OUT_OF_MEMORY;
|
|
}
|
|
|
|
err = act->unpack_double(values, &size);
|
|
if (!err) {
|
|
for (j = 0; j < len; j++) {
|
|
val_array[j] = values[index_array[j]];
|
|
}
|
|
}
|
|
|
|
grib_context_free(h->context, values);
|
|
|
|
return err;
|
|
}
|
|
int grib_get_float_elements(const grib_handle* h, const char* name, const int* index_array, long len, float* val_array)
|
|
{
|
|
return GRIB_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
int grib_get_string_internal(grib_handle* h, const char* name, char* val, size_t* length)
|
|
{
|
|
int ret = grib_get_string(h, name, val, length);
|
|
|
|
if (ret != GRIB_SUCCESS)
|
|
grib_context_log(h->context, GRIB_LOG_ERROR,
|
|
"Unable to get %s as string (%s)",
|
|
name, grib_get_error_message(ret));
|
|
|
|
return ret;
|
|
}
|
|
|
|
int grib_get_string(const grib_handle* h, const char* name, char* val, size_t* length)
|
|
{
|
|
grib_accessor* a = NULL;
|
|
grib_accessors_list* al = NULL;
|
|
int ret = 0;
|
|
|
|
if (name[0] == '/') {
|
|
al = grib_find_accessors_list(h, name);
|
|
if (!al)
|
|
return GRIB_NOT_FOUND;
|
|
ret = al->accessor->unpack_string(val, length);
|
|
grib_context_free(h->context, al);
|
|
return ret;
|
|
}
|
|
else {
|
|
a = grib_find_accessor(h, name);
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
return a->unpack_string(val, length);
|
|
}
|
|
}
|
|
|
|
// int grib_get_bytes_internal(const grib_handle* h, const char* name, unsigned char* val, size_t* length)
|
|
// {
|
|
// int ret = grib_get_bytes(h, name, val, length);
|
|
// if (ret != GRIB_SUCCESS)
|
|
// grib_context_log(h->context, GRIB_LOG_ERROR,
|
|
// "Unable to get %s as bytes (%s)",
|
|
// name, grib_get_error_message(ret));
|
|
// return ret;
|
|
// }
|
|
|
|
int grib_get_bytes(const grib_handle* h, const char* name, unsigned char* val, size_t* length)
|
|
{
|
|
int err = 0;
|
|
grib_accessor* act = grib_find_accessor(h, name);
|
|
err = act ? act->unpack_bytes(val, length) : GRIB_NOT_FOUND;
|
|
if (err)
|
|
grib_context_log(h->context, GRIB_LOG_ERROR,
|
|
"grib_get_bytes %s failed %s", name, grib_get_error_message(err));
|
|
return err;
|
|
}
|
|
|
|
int grib_get_native_type(const grib_handle* h, const char* name, int* type)
|
|
{
|
|
grib_accessors_list* al = NULL;
|
|
grib_accessor* a = NULL;
|
|
*type = GRIB_TYPE_UNDEFINED;
|
|
|
|
DEBUG_ASSERT(name != NULL && strlen(name) > 0);
|
|
|
|
if (name[0] == '/') {
|
|
al = grib_find_accessors_list(h, name);
|
|
if (!al)
|
|
return GRIB_NOT_FOUND;
|
|
*type = al->accessor->get_native_type();
|
|
grib_context_free(h->context, al);
|
|
}
|
|
else {
|
|
a = grib_find_accessor(h, name);
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
*type = a->get_native_type();
|
|
}
|
|
|
|
return GRIB_SUCCESS;
|
|
}
|
|
|
|
// const char* grib_get_accessor_class_name(grib_handle* h, const char* name)
|
|
// {
|
|
// grib_accessor* act = grib_find_accessor(h, name);
|
|
// return act ? act->cclass->name : NULL;
|
|
// }
|
|
|
|
template <typename T>
|
|
static int _grib_get_array_internal(const grib_handle* h, grib_accessor* a, T* val, size_t buffer_len, size_t* decoded_length)
|
|
{
|
|
static_assert(std::is_floating_point<T>::value, "Requires floating point numbers");
|
|
if (a) {
|
|
int err = _grib_get_array_internal<T>(h, a->same_, val, buffer_len, decoded_length);
|
|
|
|
if (err == GRIB_SUCCESS) {
|
|
size_t len = buffer_len - *decoded_length;
|
|
if constexpr (std::is_same<T, double>::value) {
|
|
err = a->unpack_double(val + *decoded_length, &len);
|
|
}
|
|
else if constexpr (std::is_same<T, float>::value) {
|
|
err = a->unpack_float(val + *decoded_length, &len);
|
|
}
|
|
*decoded_length += len;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
else {
|
|
return GRIB_SUCCESS;
|
|
}
|
|
}
|
|
|
|
int grib_get_double_array_internal(const grib_handle* h, const char* name, double* val, size_t* length)
|
|
{
|
|
return grib_get_array_internal<double>(h, name, val, length);
|
|
}
|
|
|
|
int grib_get_float_array_internal(const grib_handle* h, const char* name, float* val, size_t* length)
|
|
{
|
|
return grib_get_array_internal<float>(h, name, val, length);
|
|
}
|
|
|
|
int grib_get_double_array(const grib_handle* h, const char* name, double* val, size_t* length)
|
|
{
|
|
size_t len = *length;
|
|
grib_accessor* a = NULL;
|
|
grib_accessors_list* al = NULL;
|
|
int ret = 0;
|
|
|
|
if (name[0] == '/') {
|
|
al = grib_find_accessors_list(h, name);
|
|
if (!al)
|
|
return GRIB_NOT_FOUND;
|
|
ret = al->unpack_double(val, length);
|
|
grib_accessors_list_delete(h->context, al);
|
|
return ret;
|
|
}
|
|
else {
|
|
a = grib_find_accessor(h, name);
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
if (name[0] == '#') {
|
|
return a->unpack_double(val, length);
|
|
}
|
|
else {
|
|
*length = 0;
|
|
return _grib_get_array_internal<double>(h, a, val, len, length);
|
|
}
|
|
}
|
|
}
|
|
|
|
int grib_get_float_array(const grib_handle* h, const char* name, float* val, size_t *length)
|
|
{
|
|
size_t len = *length;
|
|
grib_accessor* a = grib_find_accessor(h, name);
|
|
if (!a) return GRIB_NOT_FOUND;
|
|
|
|
//[> TODO: For now only GRIB supported... no BUFR keys <]
|
|
if (h->product_kind != PRODUCT_GRIB) {
|
|
//grib_context_log(h->context, GRIB_LOG_ERROR, "grib_get_float_array only supported for GRIB");
|
|
return GRIB_NOT_IMPLEMENTED;
|
|
}
|
|
ECCODES_ASSERT(name[0]!='/');
|
|
ECCODES_ASSERT(name[0]!='#');
|
|
*length = 0;
|
|
return _grib_get_array_internal<float>(h,a,val,len,length);
|
|
}
|
|
|
|
template <>
|
|
int grib_get_array<float>(const grib_handle* h, const char* name, float* val, size_t *length)
|
|
{
|
|
return grib_get_float_array(h, name, val, length);
|
|
}
|
|
|
|
template <>
|
|
int grib_get_array<double>(const grib_handle* h, const char* name, double* val, size_t* length)
|
|
{
|
|
return grib_get_double_array(h, name, val, length);
|
|
}
|
|
|
|
int grib_get_string_length_acc(grib_accessor* a, size_t* size)
|
|
{
|
|
size_t s = 0;
|
|
|
|
*size = 0;
|
|
while (a) {
|
|
s = a->string_length();
|
|
if (s > *size)
|
|
*size = s;
|
|
a = a->same_;
|
|
}
|
|
(*size) += 1;
|
|
|
|
return GRIB_SUCCESS;
|
|
}
|
|
|
|
int grib_get_string_length(const grib_handle* h, const char* name, size_t* size)
|
|
{
|
|
grib_accessor* a = NULL;
|
|
grib_accessors_list* al = NULL;
|
|
int ret = 0;
|
|
|
|
if (name[0] == '/') {
|
|
al = grib_find_accessors_list(h, name);
|
|
if (!al)
|
|
return GRIB_NOT_FOUND;
|
|
ret = grib_get_string_length_acc(al->accessor, size);
|
|
grib_context_free(h->context, al);
|
|
return ret;
|
|
}
|
|
else {
|
|
a = grib_find_accessor(h, name);
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
return grib_get_string_length_acc(a, size);
|
|
}
|
|
}
|
|
|
|
int grib_get_size_acc(const grib_handle* h, grib_accessor* a, size_t* size)
|
|
{
|
|
long count = 0;
|
|
int err = 0;
|
|
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
|
|
*size = 0;
|
|
while (a) {
|
|
if (err == 0) {
|
|
err = a->value_count(&count);
|
|
if (err)
|
|
return err;
|
|
*size += count;
|
|
}
|
|
a = a->same_;
|
|
}
|
|
return GRIB_SUCCESS;
|
|
}
|
|
|
|
int grib_get_size(const grib_handle* ch, const char* name, size_t* size)
|
|
{
|
|
grib_handle* h = (grib_handle*)ch;
|
|
grib_accessor* a = NULL;
|
|
grib_accessors_list* al = NULL;
|
|
int ret = 0;
|
|
*size = 0;
|
|
|
|
if (name[0] == '/') {
|
|
al = grib_find_accessors_list(h, name);
|
|
if (!al)
|
|
return GRIB_NOT_FOUND;
|
|
ret = al->value_count(size);
|
|
grib_accessors_list_delete(h->context, al);
|
|
return ret;
|
|
}
|
|
else {
|
|
a = grib_find_accessor(h, name);
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
if (name[0] == '#') {
|
|
long count = *size;
|
|
ret = a->value_count(&count);
|
|
*size = count;
|
|
return ret;
|
|
}
|
|
else
|
|
return grib_get_size_acc(h, a, size);
|
|
}
|
|
}
|
|
|
|
int grib_get_length(const grib_handle* h, const char* name, size_t* length)
|
|
{
|
|
return grib_get_string_length(h, name, length);
|
|
}
|
|
|
|
// int grib_get_count(grib_handle* h, const char* name, size_t* size)
|
|
// {
|
|
// grib_accessor* a = grib_find_accessor(h, name);
|
|
// if (!a)
|
|
// return GRIB_NOT_FOUND;
|
|
// *size = 0;
|
|
// while (a) {
|
|
// (*size)++;
|
|
// a = a->same_;
|
|
// }
|
|
// return GRIB_SUCCESS;
|
|
// }
|
|
|
|
int grib_get_offset(const grib_handle* ch, const char* key, size_t* val)
|
|
{
|
|
const grib_handle* h = (grib_handle*)ch;
|
|
grib_accessor* act = grib_find_accessor(h, key);
|
|
if (act) {
|
|
*val = (size_t) act->byte_offset();
|
|
return GRIB_SUCCESS;
|
|
}
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
static int grib_get_string_array_internal_(const grib_handle* h, grib_accessor* a, char** val, size_t buffer_len, size_t* decoded_length)
|
|
{
|
|
if (a) {
|
|
int err = grib_get_string_array_internal_(h, a->same_, val, buffer_len, decoded_length);
|
|
|
|
if (err == GRIB_SUCCESS) {
|
|
size_t len = buffer_len - *decoded_length;
|
|
err = a->unpack_string_array(val + *decoded_length, &len);
|
|
*decoded_length += len;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
else {
|
|
return GRIB_SUCCESS;
|
|
}
|
|
}
|
|
|
|
int grib_get_string_array(const grib_handle* h, const char* name, char** val, size_t* length)
|
|
{
|
|
size_t len = *length;
|
|
grib_accessor* a = NULL;
|
|
grib_accessors_list* al = NULL;
|
|
int ret = 0;
|
|
|
|
if (name[0] == '/') {
|
|
al = grib_find_accessors_list(h, name);
|
|
if (!al)
|
|
return GRIB_NOT_FOUND;
|
|
ret = al->unpack_string(val, length);
|
|
grib_context_free(h->context, al);
|
|
return ret;
|
|
}
|
|
else {
|
|
a = grib_find_accessor(h, name);
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
if (name[0] == '#') {
|
|
return a->unpack_string_array(val, length);
|
|
}
|
|
else {
|
|
*length = 0;
|
|
return grib_get_string_array_internal_(h, a, val, len, length);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int _grib_get_long_array_internal(const grib_handle* h, grib_accessor* a, long* val, size_t buffer_len, size_t* decoded_length)
|
|
{
|
|
if (a) {
|
|
int err = _grib_get_long_array_internal(h, a->same_, val, buffer_len, decoded_length);
|
|
|
|
if (err == GRIB_SUCCESS) {
|
|
size_t len = buffer_len - *decoded_length;
|
|
err = a->unpack_long(val + *decoded_length, &len);
|
|
*decoded_length += len;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
else {
|
|
return GRIB_SUCCESS;
|
|
}
|
|
}
|
|
|
|
int grib_get_long_array_internal(grib_handle* h, const char* name, long* val, size_t* length)
|
|
{
|
|
int ret = grib_get_long_array(h, name, val, length);
|
|
|
|
if (ret != GRIB_SUCCESS)
|
|
grib_context_log(h->context, GRIB_LOG_ERROR,
|
|
"Unable to get %s as long array (%s)",
|
|
name, grib_get_error_message(ret));
|
|
|
|
return ret;
|
|
}
|
|
|
|
int grib_get_long_array(const grib_handle* h, const char* name, long* val, size_t* length)
|
|
{
|
|
size_t len = *length;
|
|
grib_accessor* a = NULL;
|
|
grib_accessors_list* al = NULL;
|
|
int ret = 0;
|
|
|
|
if (name[0] == '/') {
|
|
al = grib_find_accessors_list(h, name);
|
|
if (!al)
|
|
return GRIB_NOT_FOUND;
|
|
ret = al->unpack_long(val, length);
|
|
grib_context_free(h->context, al);
|
|
}
|
|
else {
|
|
a = grib_find_accessor(h, name);
|
|
if (!a)
|
|
return GRIB_NOT_FOUND;
|
|
if (name[0] == '#') {
|
|
return a->unpack_long(val, length);
|
|
}
|
|
else {
|
|
*length = 0;
|
|
return _grib_get_long_array_internal(h, a, val, len, length);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// static void grib_clean_key_value(grib_context* c, grib_key_value_list* kv)
|
|
// {
|
|
// if (kv->long_value)
|
|
// grib_context_free(c, kv->long_value);
|
|
// kv->long_value = NULL;
|
|
// if (kv->double_value)
|
|
// grib_context_free(c, kv->double_value);
|
|
// kv->double_value = NULL;
|
|
// if (kv->string_value)
|
|
// grib_context_free(c, kv->string_value);
|
|
// kv->string_value = NULL;
|
|
// if (kv->namespace_value)
|
|
// grib_key_value_list_delete(c, kv->namespace_value);
|
|
// kv->namespace_value = NULL;
|
|
// kv->error = 0;
|
|
// kv->has_value = 0;
|
|
// kv->size = 0;
|
|
// }
|
|
|
|
// static int grib_get_key_value(grib_handle* h, grib_key_value_list* kv)
|
|
// {
|
|
// int err = 0;
|
|
// size_t size = 0;
|
|
// grib_keys_iterator* iter = NULL;
|
|
// grib_key_value_list* list = NULL;
|
|
// if (kv->has_value)
|
|
// grib_clean_key_value(h->context, kv);
|
|
// err = grib_get_size(h, kv->name, &size);
|
|
// if (err) {
|
|
// kv->error = err;
|
|
// return err;
|
|
// }
|
|
// if (size == 0)
|
|
// size = 512;
|
|
// switch (kv->type) {
|
|
// case GRIB_TYPE_LONG:
|
|
// kv->long_value = (long*)grib_context_malloc_clear(h->context, size * sizeof(long));
|
|
// err = grib_get_long_array(h, kv->name, kv->long_value, &size);
|
|
// kv->error = err;
|
|
// break;
|
|
// case GRIB_TYPE_DOUBLE:
|
|
// kv->double_value = (double*)grib_context_malloc_clear(h->context, size * sizeof(double));
|
|
// err = grib_get_double_array(h, kv->name, kv->double_value, &size);
|
|
// kv->error = err;
|
|
// break;
|
|
// case GRIB_TYPE_STRING:
|
|
// grib_get_string_length(h, kv->name, &size);
|
|
// kv->string_value = (char*)grib_context_malloc_clear(h->context, size * sizeof(char));
|
|
// err = grib_get_string(h, kv->name, kv->string_value, &size);
|
|
// kv->error = err;
|
|
// break;
|
|
// case GRIB_TYPE_BYTES:
|
|
// kv->string_value = (char*)grib_context_malloc_clear(h->context, size * sizeof(char));
|
|
// err = grib_get_bytes(h, kv->name, (unsigned char*)kv->string_value, &size);
|
|
// kv->error = err;
|
|
// break;
|
|
// case CODES_NAMESPACE:
|
|
// iter = grib_keys_iterator_new(h, 0, kv->name);
|
|
// list = (grib_key_value_list*)grib_context_malloc_clear(h->context, sizeof(grib_key_value_list));
|
|
// kv->namespace_value = list;
|
|
// while (grib_keys_iterator_next(iter)) {
|
|
// list->name = grib_keys_iterator_get_name(iter);
|
|
// err = grib_get_native_type(h, list->name, &(list->type));
|
|
// if (err)
|
|
// return err;
|
|
// err = grib_get_key_value(h, list);
|
|
// if (err)
|
|
// return err;
|
|
// list->next = (grib_key_value_list*)grib_context_malloc_clear(h->context, sizeof(grib_key_value_list));
|
|
// list = list->next;
|
|
// }
|
|
// grib_keys_iterator_delete(iter);
|
|
// break;
|
|
// default:
|
|
// err = grib_get_native_type(h, kv->name, &(kv->type));
|
|
// if (err)
|
|
// return err;
|
|
// err = grib_get_key_value(h, kv);
|
|
// break;
|
|
// }
|
|
// kv->has_value = 1;
|
|
// return err;
|
|
// }
|
|
|
|
// grib_key_value_list* grib_key_value_list_clone(grib_context* c, grib_key_value_list* list)
|
|
// {
|
|
// grib_key_value_list* next = list;
|
|
// grib_key_value_list* the_clone = (grib_key_value_list*)grib_context_malloc_clear(c, sizeof(grib_key_value_list));
|
|
// grib_key_value_list* p = the_clone;
|
|
// while (next && next->name) {
|
|
// p->name = grib_context_strdup(c, next->name);
|
|
// p->type = next->type;
|
|
// next = next->next;
|
|
// }
|
|
// return the_clone;
|
|
// }
|
|
|
|
// void grib_key_value_list_delete(grib_context* c, grib_key_value_list* kvl)
|
|
// {
|
|
// grib_key_value_list* next = kvl;
|
|
// grib_key_value_list* p = NULL;
|
|
// while (next) {
|
|
// p = next->next;
|
|
// if (next->type == CODES_NAMESPACE)
|
|
// grib_key_value_list_delete(c, next->namespace_value);
|
|
// grib_clean_key_value(c, next);
|
|
// grib_context_free(c, next);
|
|
// next = p;
|
|
// }
|
|
// }
|
|
|
|
// int grib_get_key_value_list(grib_handle* h, grib_key_value_list* list)
|
|
// {
|
|
// int ret = 0;
|
|
// grib_key_value_list* kvl = list;
|
|
// while (kvl) {
|
|
// ret = grib_get_key_value(h, kvl);
|
|
// kvl = kvl->next;
|
|
// }
|
|
// return ret;
|
|
// }
|
|
|
|
// int grib_get_values(grib_handle* h, grib_values* args, size_t count)
|
|
// {
|
|
// int ret = 0;
|
|
// int i = 0;
|
|
// for (i = 0; i < count; i++) {
|
|
// char buff[1024] = {0,};
|
|
// size_t len = sizeof(buff) / sizeof(*buff);
|
|
// if (!args[i].name) {
|
|
// args[i].error = GRIB_INVALID_ARGUMENT;
|
|
// continue;
|
|
// }
|
|
// if (args[i].type == 0) {
|
|
// args[i].error = grib_get_native_type(h, args[i].name, &(args[i].type));
|
|
// if (args[i].error != GRIB_SUCCESS)
|
|
// ret = args[i].error;
|
|
// }
|
|
// switch (args[i].type) {
|
|
// case GRIB_TYPE_LONG:
|
|
// args[i].error = grib_get_long(h, args[i].name, &(args[i].long_value));
|
|
// if (args[i].error != GRIB_SUCCESS)
|
|
// ret = args[i].error;
|
|
// break;
|
|
// case GRIB_TYPE_DOUBLE:
|
|
// args[i].error = grib_get_double(h, args[i].name, &(args[i].double_value));
|
|
// if (args[i].error != GRIB_SUCCESS)
|
|
// ret = args[i].error;
|
|
// break;
|
|
// case GRIB_TYPE_STRING:
|
|
// args[i].error = grib_get_string(h, args[i].name, buff, &len);
|
|
// args[i].string_value = strdup(buff);
|
|
// if (args[i].error != GRIB_SUCCESS)
|
|
// ret = args[i].error;
|
|
// break;
|
|
// default:
|
|
// args[i].error = grib_get_string(h, args[i].name, buff, &len);
|
|
// args[i].string_value = strdup(buff);
|
|
// if (args[i].error != GRIB_SUCCESS)
|
|
// ret = args[i].error;
|
|
// break;
|
|
// }
|
|
// }
|
|
// return ret;
|
|
// }
|
|
|
|
int grib_set_values(grib_handle* h, grib_values* args, size_t count)
|
|
{
|
|
// The default behaviour is to print any error messages (not silent)
|
|
return grib_set_values_silent(h, args, count, /*silent=*/0);
|
|
}
|
|
|
|
int grib_set_values_silent(grib_handle* h, grib_values* args, size_t count, int silent)
|
|
{
|
|
int i, error = 0;
|
|
int err = 0;
|
|
size_t len;
|
|
int more = 1;
|
|
int stack = h->values_stack++;
|
|
|
|
ECCODES_ASSERT(h->values_stack < MAX_SET_VALUES - 1);
|
|
|
|
h->values[stack] = args;
|
|
h->values_count[stack] = count;
|
|
|
|
if (h->context->debug) {
|
|
for (i = 0; i < count; i++) {
|
|
grib_print_values("ECCODES DEBUG about to set key/value pair", &args[i], stderr, 1);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < count; i++)
|
|
args[i].error = GRIB_NOT_FOUND;
|
|
|
|
while (more) {
|
|
more = 0;
|
|
for (i = 0; i < count; i++) {
|
|
if (args[i].error != GRIB_NOT_FOUND)
|
|
continue;
|
|
|
|
switch (args[i].type) {
|
|
case GRIB_TYPE_LONG:
|
|
error = grib_set_long(h, args[i].name, args[i].long_value);
|
|
args[i].error = error;
|
|
if (args[i].error == GRIB_SUCCESS)
|
|
more = 1;
|
|
break;
|
|
|
|
case GRIB_TYPE_DOUBLE:
|
|
args[i].error = grib_set_double(h, args[i].name, args[i].double_value);
|
|
if (args[i].error == GRIB_SUCCESS)
|
|
more = 1;
|
|
break;
|
|
|
|
case GRIB_TYPE_STRING:
|
|
len = strlen(args[i].string_value);
|
|
args[i].error = grib_set_string(h, args[i].name, args[i].string_value, &len);
|
|
if (args[i].error == GRIB_SUCCESS)
|
|
more = 1;
|
|
break;
|
|
|
|
case GRIB_TYPE_MISSING:
|
|
args[i].error = grib_set_missing(h, args[i].name);
|
|
if (args[i].error == GRIB_SUCCESS)
|
|
more = 1;
|
|
break;
|
|
|
|
default:
|
|
if (!silent)
|
|
grib_context_log(h->context, GRIB_LOG_ERROR, "grib_set_values[%d] %s invalid type %d", i, args[i].name, args[i].type);
|
|
args[i].error = GRIB_INVALID_ARGUMENT;
|
|
break;
|
|
}
|
|
// if (args[i].error != GRIB_SUCCESS)
|
|
// grib_context_log(h->context,GRIB_LOG_ERROR,"Unable to set %s (%s)",args[i].name,grib_get_error_message(args[i].error));
|
|
}
|
|
}
|
|
|
|
h->values[stack] = NULL;
|
|
h->values_count[stack] = 0;
|
|
|
|
h->values_stack--;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (args[i].error != GRIB_SUCCESS) {
|
|
if (!silent) {
|
|
grib_context_log(h->context, GRIB_LOG_ERROR,
|
|
"grib_set_values[%d] %s (type=%s) failed: %s (message %d)",
|
|
i, args[i].name, grib_get_type_name(args[i].type),
|
|
grib_get_error_message(args[i].error), h->context->handle_file_count);
|
|
}
|
|
err = err == GRIB_SUCCESS ? args[i].error : err;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
int grib_get_nearest_smaller_value(grib_handle* h, const char* name,
|
|
double val, double* nearest)
|
|
{
|
|
grib_accessor* act = grib_find_accessor(h, name);
|
|
ECCODES_ASSERT(act);
|
|
return act->nearest_smaller_value(val, nearest);
|
|
}
|
|
|
|
void grib_print_values(const char* title, const grib_values* values, FILE* out, int count)
|
|
{
|
|
ECCODES_ASSERT(values);
|
|
for (int i = 0; i < count; ++i) {
|
|
const grib_values aVal = values[i];
|
|
fprintf(out, "%s: %s=", title, aVal.name);
|
|
switch (aVal.type) {
|
|
case GRIB_TYPE_LONG:
|
|
fprintf(out, "%ld", aVal.long_value);
|
|
break;
|
|
case GRIB_TYPE_DOUBLE:
|
|
fprintf(out, "%g", aVal.double_value);
|
|
break;
|
|
case GRIB_TYPE_STRING:
|
|
fprintf(out, "%s", aVal.string_value);
|
|
break;
|
|
}
|
|
fprintf(out, " (type=%s)", grib_get_type_name(aVal.type));
|
|
if (aVal.error) fprintf(out, "\t(%s)\n", grib_get_error_message(aVal.error));
|
|
else fprintf(out, "\n");
|
|
}
|
|
}
|
|
|
|
int grib_values_check(grib_handle* h, grib_values* values, int count)
|
|
{
|
|
int i = 0;
|
|
long long_value;
|
|
double double_value;
|
|
unsigned char ubuff[1024] = {0,};
|
|
char buff[1024] = {0,};
|
|
size_t len = 1024;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (values[i].type == 0) {
|
|
values[i].error = GRIB_INVALID_TYPE;
|
|
return values[i].error;
|
|
}
|
|
|
|
switch (values[i].type) {
|
|
case GRIB_TYPE_LONG:
|
|
values[i].error = grib_get_long(h, values[i].name, &long_value);
|
|
if (values[i].error != GRIB_SUCCESS)
|
|
return values[i].error;
|
|
if (long_value != values[i].long_value) {
|
|
values[i].error = GRIB_VALUE_DIFFERENT;
|
|
return values[i].error;
|
|
}
|
|
break;
|
|
|
|
case GRIB_TYPE_DOUBLE:
|
|
values[i].error = grib_get_double(h, values[i].name, &double_value);
|
|
if (values[i].error != GRIB_SUCCESS)
|
|
return values[i].error;
|
|
if (double_value != values[i].double_value) {
|
|
values[i].error = GRIB_VALUE_DIFFERENT;
|
|
return values[i].error;
|
|
}
|
|
break;
|
|
|
|
case GRIB_TYPE_STRING:
|
|
values[i].error = grib_get_string(h, values[i].name, buff, &len);
|
|
if (values[i].error != GRIB_SUCCESS)
|
|
return values[i].error;
|
|
if (strcmp(values[i].string_value, buff)) {
|
|
values[i].error = GRIB_VALUE_DIFFERENT;
|
|
return values[i].error;
|
|
}
|
|
break;
|
|
|
|
case GRIB_TYPE_BYTES:
|
|
values[i].error = grib_get_bytes(h, values[i].name, ubuff, &len);
|
|
if (values[i].error != GRIB_SUCCESS)
|
|
return values[i].error;
|
|
if (memcmp(values[i].string_value, ubuff, len)) {
|
|
values[i].error = GRIB_VALUE_DIFFERENT;
|
|
return values[i].error;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
values[i].error = GRIB_INVALID_TYPE;
|
|
return values[i].error;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int codes_copy_key(grib_handle* h1, grib_handle* h2, const char* key, int type)
|
|
{
|
|
double d;
|
|
double* ad;
|
|
long l;
|
|
long* al;
|
|
char* s = 0;
|
|
char** as = 0;
|
|
size_t len1 = 0, len = 0;
|
|
int err = 0;
|
|
|
|
if (type != GRIB_TYPE_DOUBLE &&
|
|
type != GRIB_TYPE_LONG &&
|
|
type != GRIB_TYPE_STRING) {
|
|
err = grib_get_native_type(h1, key, &type);
|
|
if (err)
|
|
return err;
|
|
}
|
|
|
|
err = grib_get_size(h1, key, &len1);
|
|
if (err)
|
|
return err;
|
|
|
|
switch (type) {
|
|
case GRIB_TYPE_DOUBLE:
|
|
if (len1 == 1) {
|
|
err = grib_get_double(h1, key, &d);
|
|
if (err)
|
|
return err;
|
|
grib_context_log(h1->context, GRIB_LOG_DEBUG, "codes_copy_key double: %s=%g\n", key, d);
|
|
err = grib_set_double(h2, key, d);
|
|
return err;
|
|
}
|
|
else {
|
|
ad = (double*)grib_context_malloc_clear(h1->context, len1 * sizeof(double));
|
|
err = grib_get_double_array(h1, key, ad, &len1);
|
|
if (err)
|
|
return err;
|
|
err = grib_set_double_array(h2, key, ad, len1);
|
|
grib_context_free(h1->context, ad);
|
|
return err;
|
|
}
|
|
break;
|
|
case GRIB_TYPE_LONG:
|
|
if (len1 == 1) {
|
|
err = grib_get_long(h1, key, &l);
|
|
if (err)
|
|
return err;
|
|
grib_context_log(h1->context, GRIB_LOG_DEBUG, "codes_copy_key long: %s=%ld\n", key, l);
|
|
err = grib_set_long(h2, key, l);
|
|
return err;
|
|
}
|
|
else {
|
|
al = (long*)grib_context_malloc_clear(h1->context, len1 * sizeof(long));
|
|
err = grib_get_long_array(h1, key, al, &len1);
|
|
if (err)
|
|
return err;
|
|
err = grib_set_long_array(h2, key, al, len1);
|
|
grib_context_free(h1->context, al);
|
|
return err;
|
|
}
|
|
break;
|
|
case GRIB_TYPE_STRING:
|
|
err = grib_get_string_length(h1, key, &len);
|
|
if (err)
|
|
return err;
|
|
if (len1 == 1) {
|
|
s = (char*)grib_context_malloc_clear(h1->context, len);
|
|
err = grib_get_string(h1, key, s, &len);
|
|
if (err)
|
|
return err;
|
|
grib_context_log(h1->context, GRIB_LOG_DEBUG, "codes_copy_key str: %s=%s\n", key, s);
|
|
err = grib_set_string(h2, key, s, &len);
|
|
grib_context_free(h1->context, s);
|
|
return err;
|
|
}
|
|
else {
|
|
as = (char**)grib_context_malloc_clear(h1->context, len1 * sizeof(char*));
|
|
err = grib_get_string_array(h1, key, as, &len1);
|
|
if (err)
|
|
return err;
|
|
err = grib_set_string_array(h2, key, (const char**)as, len1);
|
|
return err;
|
|
}
|
|
break;
|
|
default:
|
|
return GRIB_INVALID_TYPE;
|
|
}
|
|
}
|
|
|
|
int codes_compare_key(grib_handle* h1, grib_handle* h2, const char* key, int compare_flags)
|
|
{
|
|
grib_accessor* a1 = grib_find_accessor(h1, key);
|
|
if (!a1) {
|
|
grib_context_log(h1->context, GRIB_LOG_ERROR, "Key %s not found in first message", key);
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
grib_accessor* a2 = grib_find_accessor(h2, key);
|
|
if (!a2) {
|
|
grib_context_log(h1->context, GRIB_LOG_ERROR, "Key %s not found in second message", key);
|
|
return GRIB_NOT_FOUND;
|
|
}
|
|
|
|
return a1->compare_accessors(a2, GRIB_COMPARE_TYPES);
|
|
}
|