/* * (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 #include #include /* 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 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::max(); T maxVal = -std::numeric_limits::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 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::value, "Requires floating point numbers"); if (a) { int err = _grib_get_array_internal(h, a->same_, val, buffer_len, decoded_length); if (err == GRIB_SUCCESS) { size_t len = buffer_len - *decoded_length; if constexpr (std::is_same::value) { err = a->unpack_double(val + *decoded_length, &len); } else if constexpr (std::is_same::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(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(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(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(h,a,val,len,length); } template <> int grib_get_array(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(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); }