static int get_file_size(const char *filename, int64_t *file_size) { struct stat statbuf; assert(filename != NULL && file_size != NULL); /* stat() the file to be opened */ if (stat(filename, &statbuf) != 0) { if (errno == ENOENT) { coda_set_error(CODA_ERROR_FILE_NOT_FOUND, "could not find %s", filename); } else { coda_set_error(CODA_ERROR_FILE_OPEN, "could not open %s (%s)", filename, strerror(errno)); } return -1; } /* check that the file is a regular file */ if ((statbuf.st_mode & S_IFREG) == 0) { coda_set_error(CODA_ERROR_FILE_OPEN, "could not open %s (not a regular file)", filename); return -1; } /* get file size */ *file_size = statbuf.st_size; return 0; }
/** Open a product file for reading. * This function will try to open the specified file for reading. On success a newly allocated file handle will be * returned. The memory for this file handle will be released when coda_close() is called for this handle. * \param filename Relative or full path to the product file. * \param product Pointer to the variable where the pointer to the product file handle will be storeed. * \return * \arg \c 0, Success. * \arg \c -1, Error occurred (check #coda_errno). */ LIBCODA_API int coda_open(const char *filename, coda_product **product) { coda_product_definition *definition = NULL; coda_format format; int64_t file_size; if (filename == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "filename argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (product == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "product argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (detect_definition(filename, &format, &file_size, &definition) != 0) { return -1; } if (definition != NULL && definition->root_type == NULL) { if (coda_read_product_definition(definition) != 0) { return -1; } } return open_file(filename, format, file_size, definition, product); }
static int init_SDSs(coda_hdf4_product *product) { if (SDfileinfo(product->sd_id, &(product->num_sds), &(product->num_sd_file_attributes)) != 0) { coda_set_error(CODA_ERROR_HDF4, NULL); return -1; } if (product->num_sds > 0) { int i; product->sds = malloc(product->num_sds * sizeof(coda_hdf4_SDS *)); if (product->sds == NULL) { coda_set_error(CODA_ERROR_OUT_OF_MEMORY, "out of memory (could not allocate %lu bytes) (%s:%u)", (long)product->num_sds * sizeof(coda_hdf4_SDS *), __FILE__, __LINE__); return -1; } for (i = 0; i < product->num_sds; i++) { product->sds[i] = NULL; } for (i = 0; i < product->num_sds; i++) { product->sds[i] = coda_hdf4_SDS_new(product, i); if (product->sds[i] == NULL) { return -1; } } } return 0; }
/** Find product files matching a specific filter. * With this function you can match a series of files or directories against a specific filter. The filter needs to be * provided as a string. For information about its format please look at the documentation of the codafind tool which is * also included with the CODA package. If you leave \a filefilter empty or pass a NULL pointer then each file that * can be opened by CODA will be matched positively (this has the same effect as if you had passed a filefilter "true"). * * The names of the files and directories need to be passed as an array of full/relative paths. If an entry is a * directory then all files and directories that are contained inside will be added to the filter matching. Directories * within directories are processed recursively. * * For each file that is processed a callback function, which will have to be provided by the user, will be called. * The callback function will be passed the path of the file, a status value indicating the match result, optionally * an error string in case an error happened, and the \a userdata pointer that was passed to the coda_match_filefilter() * function. * The return value of the callback function determines whether the rest of the files/directories should be processed. * If you return 0 from the callback function then processing will continue normally. If you return a different value, * then the coda_match_filefilter() function will stop further processing and return the same return value to your * program as you have returned from the callback function. It is recommended not to use -1 as return value in your * callback function, since coda_match_filefilter() will already return -1 if it encounters an error internally. * * A small example of a callback function is given below * \code{.c} * int callback(const char *filepath, coda_filefilter_status status, const char *error, void *userdata) * { * switch (status) * { * case coda_ffs_match: * printf("File \"%s\" matches filter!\n", filepath); * break; * case coda_ffs_unsupported_file: * case coda_ffs_no_match: * // don't print anything if the file does not positively match the filter * break; * default: * if (error != NULL) * { * printf("ERROR: %s\n", error); * } * break; * } * return 0; // if possible continue processing the other files * } * \endcode * * \param filefilter String containing the filter. * \param num_filepaths Number of filepaths in \a filepathlist (0 < \a num_filepaths). * \param filepathlist Array of strings containing relative or absolute paths to a series of files and/or * directories that should be matched against the filefilter. * \param callbackfunc A pointer to a function that should be called with the match result of a file that has been * processed. * \param userdata A pointer to a user definable data block that will be passed along to the user callback function. * \return * \arg \c 0, Success. * \arg \c -1, Error occurred (check #coda_errno). * \arg other, The return value from the last call to the callback function. */ LIBCODA_API int coda_match_filefilter(const char *filefilter, int num_filepaths, const char **filepathlist, int (*callbackfunc) (const char *, coda_filefilter_status, const char *, void *), void *userdata) { NameBuffer path_name; coda_expression_type result_type; coda_expression *expr; int result; int i; if (num_filepaths <= 0 || filepathlist == NULL || callbackfunc == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "invalid argument (%s:%u)", __FILE__, __LINE__); return -1; } if (filefilter == NULL || filefilter[0] == '\0') { filefilter = "true"; } if (coda_expression_from_string(filefilter, &expr) != 0) { return -1; } if (coda_expression_get_type(expr, &result_type) != 0) { coda_expression_delete(expr); return -1; } if (result_type != coda_expression_boolean) { coda_set_error(CODA_ERROR_EXPRESSION, "expression does not result in a boolean value"); coda_expression_delete(expr); return -1; } name_buffer_init(&path_name); for (i = 0; i < num_filepaths; i++) { append_string_to_name_buffer(&path_name, filepathlist[i]); result = coda_match_filepath(0, expr, &path_name, callbackfunc, userdata); if (result != 0) { name_buffer_done(&path_name); coda_expression_delete(expr); return result; } path_name.length = 0; path_name.buffer[0] = '\0'; } name_buffer_done(&path_name); coda_expression_delete(expr); return 0; }
int coda_hdf4_cursor_goto_record_field_by_index(coda_cursor *cursor, long index) { coda_hdf4_type *record_type; coda_hdf4_type *field_type; record_type = (coda_hdf4_type *)cursor->stack[cursor->n - 1].type; switch (record_type->tag) { case tag_hdf4_attributes: if (index < 0 || index >= ((coda_hdf4_attributes *)record_type)->definition->num_fields) { coda_set_error(CODA_ERROR_INVALID_INDEX, "field index (%ld) is not in the range [0,%ld) (%s:%u)", index, ((coda_hdf4_attributes *)record_type)->definition->num_fields, __FILE__, __LINE__); return -1; } field_type = ((coda_hdf4_attributes *)record_type)->attribute[index]; break; case tag_hdf4_file_attributes: if (index < 0 || index >= ((coda_hdf4_file_attributes *)record_type)->definition->num_fields) { coda_set_error(CODA_ERROR_INVALID_INDEX, "field index (%ld) is not in the range [0,%ld) (%s:%u)", index, ((coda_hdf4_file_attributes *)record_type)->definition->num_fields, __FILE__, __LINE__); return -1; } field_type = ((coda_hdf4_file_attributes *)record_type)->attribute[index]; break; case tag_hdf4_Vdata: if (index < 0 || index >= ((coda_hdf4_Vdata *)record_type)->definition->num_fields) { coda_set_error(CODA_ERROR_INVALID_INDEX, "field index (%ld) is not in the range [0,%ld) (%s:%u)", index, ((coda_hdf4_Vdata *)record_type)->definition->num_fields, __FILE__, __LINE__); return -1; } field_type = (coda_hdf4_type *)((coda_hdf4_Vdata *)record_type)->field[index]; break; case tag_hdf4_Vgroup: if (index < 0 || index >= ((coda_hdf4_Vgroup *)record_type)->definition->num_fields) { coda_set_error(CODA_ERROR_INVALID_INDEX, "field index (%ld) is not in the range [0,%ld) (%s:%u)", index, ((coda_hdf4_Vgroup *)record_type)->definition->num_fields, __FILE__, __LINE__); return -1; } field_type = ((coda_hdf4_Vgroup *)record_type)->entry[index]; break; default: assert(0); exit(1); } cursor->n++; cursor->stack[cursor->n - 1].type = (coda_dynamic_type *)field_type; cursor->stack[cursor->n - 1].index = index; cursor->stack[cursor->n - 1].bit_offset = -1; /* not applicable for HDF4 backend */ return 0; }
/** Import HARP product from file. * \ingroup harp_product * Try to import an HDF4, HDF5, or netCDF file that complies to the HARP Data Format. * You should pass a variable to \a product that was initialized with harp_product_new(). * \param filename Path to the file that is to be imported. * \param product Empty product that is to be filled with information from the imported file. * \return * \arg \c 0, Success. * \arg \c -1, Error occurred (check #harp_errno). */ LIBHARP_API int harp_import(const char *filename, harp_product **product) { harp_product *imported_product; file_format format; if (determine_file_format(filename, &format) != 0) { return -1; } switch (format) { case format_hdf4: #ifdef HAVE_HDF4 if (harp_import_hdf4(filename, &imported_product) != 0) { return -1; } break; #else coda_set_error(HARP_ERROR_NO_HDF4_SUPPORT, NULL); return -1; #endif case format_hdf5: #ifdef HAVE_HDF5 if (harp_import_hdf5(filename, &imported_product) != 0) { return -1; } break; #else coda_set_error(HARP_ERROR_NO_HDF5_SUPPORT, NULL); return -1; #endif case format_netcdf: if (harp_import_netcdf(filename, &imported_product) != 0) { return -1; } break; default: harp_set_error(HARP_ERROR_FILE_OPEN, "unsupported file format for %s", filename); return -1; } if (harp_product_verify(imported_product) != 0) { harp_product_delete(imported_product); return -1; } *product = imported_product; return 0; }
int coda_hdf4_cursor_goto_array_element(coda_cursor *cursor, int num_subs, const long subs[]) { coda_hdf4_type *base_type; long index; int num_dims; long dim[MAX_HDF4_VAR_DIMS]; int i; if (coda_hdf4_cursor_get_array_dim(cursor, &num_dims, dim) != 0) { return -1; } /* check the number of dimensions */ if (num_subs != num_dims) { coda_set_error(CODA_ERROR_ARRAY_NUM_DIMS_MISMATCH, "number of dimensions argument (%d) does not match rank of array (%d) (%s:%u)", num_subs, num_dims, __FILE__, __LINE__); return -1; } /* check the dimensions... */ index = 0; for (i = 0; i < num_dims; i++) { if (subs[i] < 0 || subs[i] >= dim[i]) { coda_set_error(CODA_ERROR_ARRAY_OUT_OF_BOUNDS, "array index (%ld) exceeds array range [0:%ld) (%s:%u)", subs[i], dim[i], __FILE__, __LINE__); return -1; } if (i > 0) { index *= dim[i]; } index += subs[i]; } if (get_array_base_type((coda_hdf4_type *)cursor->stack[cursor->n - 1].type, &base_type) != 0) { return -1; } cursor->n++; cursor->stack[cursor->n - 1].type = (coda_dynamic_type *)base_type; cursor->stack[cursor->n - 1].index = index; cursor->stack[cursor->n - 1].bit_offset = -1; /* not applicable for HDF4 backend */ return 0; }
coda_detection_rule_entry *coda_detection_rule_entry_new(const char *path) { coda_detection_rule_entry *entry; if (path != NULL) { coda_expression_type type; coda_expression *expr; if (coda_expression_from_string(path, &expr) != 0) { return NULL; } if (coda_expression_get_type(expr, &type) != 0) { coda_expression_delete(expr); return NULL; } coda_expression_delete(expr); if (type != coda_expression_node) { coda_set_error(CODA_ERROR_DATA_DEFINITION, "not a valid path for detection rule"); return NULL; } } entry = malloc(sizeof(coda_detection_rule_entry)); if (entry == NULL) { coda_set_error(CODA_ERROR_OUT_OF_MEMORY, "out of memory (could not allocate %lu bytes) (%s:%u)", (long)sizeof(coda_detection_rule_entry), __FILE__, __LINE__); return NULL; } entry->path = NULL; entry->expression = NULL; if (path != NULL) { entry->path = strdup(path); if (entry->path == NULL) { coda_set_error(CODA_ERROR_OUT_OF_MEMORY, "out of memory (could not duplicate string) (%s:%u)", __FILE__, __LINE__); free(entry); return NULL; } } return entry; }
int coda_bin_open(const char *filename, int64_t file_size, const coda_product_definition *definition, coda_product **product) { coda_bin_product *product_file; if (definition == NULL) { coda_set_error(CODA_ERROR_UNSUPPORTED_PRODUCT, NULL); return -1; } product_file = (coda_bin_product *)malloc(sizeof(coda_bin_product)); if (product_file == NULL) { coda_set_error(CODA_ERROR_OUT_OF_MEMORY, "out of memory (could not allocate %lu bytes) (%s:%u)", sizeof(coda_bin_product), __FILE__, __LINE__); return -1; } product_file->filename = NULL; product_file->file_size = file_size; product_file->format = definition->format; product_file->root_type = (coda_dynamic_type *)definition->root_type; product_file->product_definition = definition; product_file->product_variable_size = NULL; product_file->product_variable = NULL; product_file->mem_size = 0; product_file->mem_ptr = NULL; product_file->use_mmap = 0; product_file->fd = -1; product_file->filename = strdup(filename); if (product_file->filename == NULL) { coda_set_error(CODA_ERROR_OUT_OF_MEMORY, "out of memory (could not duplicate filename string) (%s:%u)", __FILE__, __LINE__); coda_bin_close((coda_product *)product_file); return -1; } if (coda_bin_product_open(product_file) != 0) { coda_bin_close((coda_product *)product_file); return -1; } *product = (coda_product *)product_file; return 0; }
int coda_hdf4_cursor_goto_next_array_element(coda_cursor *cursor) { if (coda_option_perform_boundary_checks) { long num_elements; long index; index = cursor->stack[cursor->n - 1].index + 1; cursor->n--; if (coda_hdf4_cursor_get_num_elements(cursor, &num_elements) != 0) { cursor->n++; return -1; } cursor->n++; if (index < 0 || index >= num_elements) { coda_set_error(CODA_ERROR_ARRAY_OUT_OF_BOUNDS, "array index (%ld) exceeds array range [0:%ld) (%s:%u)", index, num_elements, __FILE__, __LINE__); return -1; } } cursor->stack[cursor->n - 1].index++; return 0; }
int coda_hdf4_cursor_goto_array_element_by_index(coda_cursor *cursor, long index) { coda_hdf4_type *base_type; /* check the range for index */ if (coda_option_perform_boundary_checks) { long num_elements; if (coda_hdf4_cursor_get_num_elements(cursor, &num_elements) != 0) { return -1; } if (index < 0 || index >= num_elements) { coda_set_error(CODA_ERROR_ARRAY_OUT_OF_BOUNDS, "array index (%ld) exceeds array range [0:%ld) (%s:%u)", index, num_elements, __FILE__, __LINE__); return -1; } } if (get_array_base_type((coda_hdf4_type *)cursor->stack[cursor->n - 1].type, &base_type) != 0) { return -1; } cursor->n++; cursor->stack[cursor->n - 1].type = (coda_dynamic_type *)base_type; cursor->stack[cursor->n - 1].index = index; cursor->stack[cursor->n - 1].bit_offset = -1; /* not applicable for HDF4 backend */ return 0; }
static int detection_node_add_node(coda_detection_node *node, coda_detection_node *new_node) { int i; if (node->num_subnodes % BLOCK_SIZE == 0) { coda_detection_node **new_subnode; new_subnode = realloc(node->subnode, (node->num_subnodes + BLOCK_SIZE) * sizeof(coda_detection_node *)); if (new_subnode == NULL) { coda_set_error(CODA_ERROR_OUT_OF_MEMORY, "out of memory (could not allocate %lu bytes) (%s:%u)", (node->num_subnodes + BLOCK_SIZE) * sizeof(coda_detection_node *), __FILE__, __LINE__); return -1; } node->subnode = new_subnode; } node->subnode[node->num_subnodes] = new_node; node->num_subnodes++; /* make sure 'path' tests come before 'expression' tests */ i = node->num_subnodes - 1; while (i > 0 && node->subnode[i]->path != NULL && node->subnode[i - 1]->expression != NULL) { coda_detection_node *swapnode; swapnode = node->subnode[i]; node->subnode[i] = node->subnode[i - 1]; node->subnode[i - 1] = swapnode; i--; } return 0; }
/** Open a product file for reading using a specific format definition. * This function will try to open the specified file for reading similar to coda_open(), but instead of trying to * automatically recognise the applicable product class/type/version as coda_open() does, this function will impose * the format definition that is associated with the given \a product_class, \a product_type, and \a version parameters. * \param filename Relative or full path to the product file. * \param product_class Name of the product class for the requested format definition. * \param product_type Name of the product type for the requested format definition. * \param version Format version number of the product type definition. Use -1 to request the latest available definition. * \param product Pointer to the variable where the pointer to the product file handle will be storeed. * \return * \arg \c 0, Success. * \arg \c -1, Error occurred (check #coda_errno). */ LIBCODA_API int coda_open_as(const char *filename, const char *product_class, const char *product_type, int version, coda_product **product) { coda_product_definition *definition; int64_t file_size; if (filename == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "filename argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (product_class == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "product_class argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (product_type == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "product_type argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (product == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "product argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (get_file_size(filename, &file_size) != 0) { return -1; } if (coda_data_dictionary_get_definition(product_class, product_type, version, &definition) != 0) { return -1; } if (definition->root_type == NULL) { if (coda_read_product_definition(definition) != 0) { return -1; } } return open_file(filename, definition->format, file_size, definition, product); }
/** Get the basic file format of the product. * Possible formats are ascii, binary, xml, netcdf, grib, hdf4, cdf, and hdf5. * Mind that inside a product different typed data can exist. For instance, both xml and binary products can have * part of their content be ascii typed data. * \param product Pointer to a product file handle. * \param format Pointer to the variable where the format will be stored. * \return * \arg \c 0, Success * \arg \c -1, Error occurred (check #coda_errno). */ LIBCODA_API int coda_get_product_format(const coda_product *product, coda_format *format) { if (product == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "product file argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (format == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "format argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } *format = product->format; return 0; }
/** Get the actual file size of a product file. * \param product Pointer to a product file handle. * \param file_size Pointer to the variable where the actual file size (in bytes) of the product is stored. * \return * \arg \c 0, Success. * \arg \c -1, Error occurred (check #coda_errno). */ LIBCODA_API int coda_get_product_file_size(const coda_product *product, int64_t *file_size) { if (product == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "product file argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (file_size == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "file_size argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } *file_size = product->file_size; return 0; }
/** Get the CODA type of the root of the product. * \param product Pointer to a product file handle. * \param type Pointer to the variable where the Type handle will be stored. * \return * \arg \c 0, Success * \arg \c -1, Error occurred (check #coda_errno). */ LIBCODA_API int coda_get_product_root_type(const coda_product *product, coda_type **type) { if (product == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "product file argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (type == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "type argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } *type = coda_get_type_for_dynamic_type(product->root_type); return 0; }
/** Initializes CODA. * This function should be called before any other CODA function is called (except for coda_set_definition_path()). * * If you want to use CODA to access non self-describing products (i.e. where the definition is provided via a .codadef * file), you will have the set the CODA definition path to the location of your .codadef files before you call * coda_init(). This can be done either via coda_set_definition_path() or via the CODA_DEFINITION environment variable. * * It is valid to perform multiple calls to coda_init() after each other. Only the first call to coda_init() will do * the actual initialization and all following calls to coda_init() will only increase an initialization counter (this * also means that it is important that you set the CODA definition path before the first call to coda_init() is * performed; changing the CODA definition path afterwards will have no effect). * Each call to coda_init() needs to be matched by a call to coda_done() at clean-up time (i.e. the amount of calls * to coda_done() needs to be equal to the amount of calls to coda_init()). Only the last coda_done() call (when * the initialization counter has reached 0) will do the actual clean-up of CODA. * \return * \arg \c 0, Success. * \arg \c -1, Error occurred (check #coda_errno). */ LIBCODA_API int coda_init(void) { if (coda_init_counter == 0) { if (coda_leap_second_table_init() != 0) { return -1; } if (coda_data_dictionary_init() != 0) { return -1; } if (coda_definition_path == NULL) { if (getenv("CODA_DEFINITION") != NULL) { coda_definition_path = strdup(getenv("CODA_DEFINITION")); if (coda_definition_path == NULL) { coda_data_dictionary_done(); coda_leap_second_table_done(); coda_set_error(CODA_ERROR_OUT_OF_MEMORY, "out of memory (could not duplicate string) (%s:%u)", __FILE__, __LINE__); return -1; } } } if (coda_definition_path != NULL) { if (coda_read_definitions(coda_definition_path) != 0) { coda_data_dictionary_done(); free(coda_definition_path); coda_leap_second_table_done(); return -1; } } coda_option_perform_boundary_checks = 1; coda_option_perform_conversions = 1; #ifdef HAVE_HDF5 if (coda_hdf5_init() != 0) { coda_data_dictionary_done(); if (coda_definition_path != NULL) { free(coda_definition_path); coda_definition_path = NULL; } coda_leap_second_table_done(); return -1; } #endif } coda_init_counter++; return 0; }
int coda_detection_rule_entry_set_expression(coda_detection_rule_entry *entry, coda_expression *expression) { if (entry->expression != NULL) { coda_set_error(CODA_ERROR_DATA_DEFINITION, "detection entry already has an expression"); return -1; } entry->expression = expression; return 0; }
/** Get the filename of a product file. * This function returns the same name that was used in the coda_open() call for this product file. * The pointer to the filename string is valid as long as the file is open. When you call coda_close() on the * product file the filename string will automatically be removed and the pointer that will be stored in \a filename * will become invalid. * The name of the product file will be stored in the \a filename parameter and will be 0 terminated. * \param product Pointer to a product file handle. * \param filename Pointer to the variable where the filename of the product will be stored. * \return * \arg \c 0, Success. * \arg \c -1, Error occurred (check #coda_errno). */ LIBCODA_API int coda_get_product_filename(const coda_product *product, const char **filename) { if (product == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "product file argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } *filename = product->filename; return 0; }
int coda_detection_tree_add_rule(void *detection_tree, coda_detection_rule *detection_rule) { coda_detection_node *node; int i; if (detection_rule->num_entries == 0) { coda_set_error(CODA_ERROR_DATA_DEFINITION, "detection rule for '%s' should have at least one entry", detection_rule->product_definition->name); return -1; } node = *(coda_detection_node **)detection_tree; if (node == NULL) { node = detection_node_new(); if (node == NULL) { return -1; } *(coda_detection_node **)detection_tree = node; } for (i = 0; i < detection_rule->num_entries; i++) { node = get_node_for_entry(node, detection_rule->entry[i]->path, detection_rule->entry[i]); if (node == NULL) { return -1; } } if (node->rule != NULL) { coda_set_error(CODA_ERROR_DATA_DEFINITION, "detection rule for '%s' is shadowed by detection rule for '%s'", detection_rule->product_definition->name, node->rule->product_definition->name); return -1; } node->rule = detection_rule; return 0; }
/** Enable/Disable the use of memory mapping of files. * By default CODA uses a technique called 'memory mapping' to open and access data from product files. * The memory mapping approach is a very fast approach that uses the mmap() function to (as the term suggests) map * a file in memory. Accessing data from a file using mmap() greatly outperforms the alternative approach of reading * data using the open()/read() combination (often by a factor of 5 and sometimes even more). * * The downside of mapping a file into memory is that it takes away valuable address space. When you run a 32-bit * Operating System your maximum addressable memory range is 4GB (or 2GB) and if you simultaneously try to keep a few * large product files open your memory space can quickly become full. Opening additional files will then produce 'out * of memory' errors. Note that this 'out of memory' situation has nothing to do with the amount of RAM you have * installed in your computer. It is only related to the size of a memory pointer on your system, which is limited to * 4GB for a 32 bits pointer. * * If you are using CODA in a situation where you need to have multiple large product files open at the same time you * can turn off the use of memory mapping by using this function. Disabling the use of mmap() means that CODA will fall * back to the mechanism of open()/read(). * * In addition, the open()/read() functionality in CODA is able to handle files that are over 4GB in size. If you are * running a 32-bit operating system or if your system does not support a 64-bit version of mmap then you can still * access such large files by disabling the mmap functionality and falling back to the open()/read() mechanism. * * \note If you change the memory mapping usage option, the new setting will only be applicable for files that will be * opened after you changed the option. Any files that were already open will keep using the mechanism with which they * were opened. * * \param enable * \arg 0: Disable the use of memory mapping. * \arg 1: Enable the use of memory mapping. * \return * \arg \c 0, Success. * \arg \c -1, Error occurred (check #coda_errno). */ LIBCODA_API int coda_set_option_use_mmap(int enable) { if (!(enable == 0 || enable == 1)) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "enable argument (%d) is not valid (%s:%u)", enable, __FILE__, __LINE__); return -1; } coda_option_use_mmap = enable; return 0; }
/** Enable/Disable boundary checking. * By default all functions in libcoda perform boundary checks. However some boundary checks are quite compute * intensive. In order to increase performance you can turn off those compute intensive boundary checks with this * option. The boundary checks that are affected by this option are the ones in * coda_cursor_goto_array_element_by_index() and coda_cursor_goto_next_array_element(). * Some internal functions of libcoda also call these functions so you might see speed improvements for other functions * too if you disable the boundary checks. * Mind that this option does not control the out-of-bounds check for trying to read beyond the end of the product * (i.e. #CODA_ERROR_OUT_OF_BOUNDS_READ). * \param enable * \arg 0: Disable boundary checking. * \arg 1: Enable boundary checking. * \return * \arg \c 0, Success. * \arg \c -1, Error occurred (check #coda_errno). */ LIBCODA_API int coda_set_option_perform_boundary_checks(int enable) { if (enable != 0 && enable != 1) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "enable argument (%d) is not valid (%s:%u)", enable, __FILE__, __LINE__); return -1; } coda_option_perform_boundary_checks = enable; return 0; }
/** Enable/Disable the use of special types. * The CODA type system contains a series of special types that were introduced to make it easier for the user to * read certain types of information. Examples of special types are the 'time', 'complex', and 'no data' * types. Each special data type is an abstraction on top of another non-special data type. Sometimes you want to * access a file using just the non-special data types (e.g. if you want to get to the raw time data in a file). * CODA already contains the coda_cursor_use_base_type_of_special_type() function that allows you to reinterpret the * current special data type using the base type of the special type. However, if you enable the bypassing of special * types option then CODA automatically calls the coda_cursor_use_base_type_of_special_type() for you whenever you move * a cursor to a data item that is of a special type. * By default bypassing of special types is disabled. * \note Bypassing of special types only works on CODA cursors and not on coda_type objects * (e.g. if a record field is of a special type the coda_type_get_record_field_type() function will still give you the * special type and not the non-special base type). * \param enable * \arg 0: Disable bypassing of special types. * \arg 1: Enable bypassing of special types. * \return * \arg \c 0, Success. * \arg \c -1, Error occurred (check #coda_errno). */ LIBCODA_API int coda_set_option_bypass_special_types(int enable) { if (enable != 0 && enable != 1) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "enable argument (%d) is not valid (%s:%u)", enable, __FILE__, __LINE__); return -1; } coda_option_bypass_special_types = enable; return 0; }
/** Get the value for a product variable. * CODA supports a mechanism called product variables to store frequently needed information of a product (i.e. * information that is needed to calculate byte offsets or array sizes within a product). With this function you * can retrieve the values for those product variables (consult the CODA Product Definition Documentation for an * overview of product variables for a certain product type). * Product variables can be one dimensional arrays, in which case you will have to pass an array index using the * \a index parameter. If the product variable is a scalar you should pass 0 for \a index. * The value of a product variable is always a 64-bit integer and will be stored in \a value. * \param product Pointer to a product file handle. * \param variable The name of the product variable. * \param index The array index of the product variable (pass 0 if the variable is a scalar). * \param value Pointer to the variable where the product variable value will be stored. * \return * \arg \c 0, Success * \arg \c -1, Error occurred (check #coda_errno). */ LIBCODA_API int coda_get_product_variable_value(coda_product *product, const char *variable, long index, int64_t *value) { int64_t *variable_ptr; long size; if (product == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "product file argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (variable == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "variable argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } /* use the size retrieval function to check the existence of the variable */ if (coda_product_variable_get_size(product, variable, &size) != 0) { coda_set_error(CODA_ERROR_INVALID_NAME, "product variable %s not available", variable); return -1; } if (index < 0 || index >= size) { coda_set_error(CODA_ERROR_INVALID_INDEX, "request for index (%ld) exceeds size of product variable %s", index, variable); return -1; } if (coda_product_variable_get_pointer(product, variable, index, &variable_ptr) != 0) { return -1; } *value = *variable_ptr; return 0; }
int coda_detection_rule_add_entry(coda_detection_rule *detection_rule, coda_detection_rule_entry *entry) { coda_detection_rule_entry **new_entry; if (entry->path == NULL && entry->expression == NULL) { coda_set_error(CODA_ERROR_DATA_DEFINITION, "detection entry should have a path and/or an expression"); return -1; } new_entry = realloc(detection_rule->entry, (detection_rule->num_entries + 1) * sizeof(coda_detection_rule_entry *)); if (new_entry == NULL) { coda_set_error(CODA_ERROR_OUT_OF_MEMORY, "out of memory (could not allocate %lu bytes) (%s:%u)", (detection_rule->num_entries + 1) * sizeof(coda_detection_rule_entry *), __FILE__, __LINE__); return -1; } detection_rule->entry = new_entry; detection_rule->num_entries++; detection_rule->entry[detection_rule->num_entries - 1] = entry; return 0; }
/** Get path to the coda definition file that describes the format for this product. * This function will return a full path to the coda definition (.codadef) file that contains the format description * for this product. If the format is not taken from an external coda definition description but based on the * self-describing format information from the file itself or based on a hardcoded format definition within one of the * coda backends then \a definition_file will be set to NULL. * \param product Pointer to a product file handle. * \param definition_file Pointer to the variable where the path to used coda definition file will be stored (or NULL if * not applicable). * \return * \arg \c 0, Success. * \arg \c -1, Error occurred (check #coda_errno). */ LIBCODA_API int coda_get_product_definition_file(const coda_product *product, const char **definition_file) { if (product == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "product file argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (definition_file == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "definition_file argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (product->product_definition != NULL) { *definition_file = product->product_definition->product_type->product_class->definition_file; } else { *definition_file = NULL; } return 0; }
/** Export HARP product to a file. * \ingroup harp_product * Export product to an HDF4, HDF5, or netCDF file that complies to the HARP Data Format. * \param filename Path to the file to which the product is to be exported. * \param export_format Either "HDF4", "HDF5", or "netCDF". * \param product Product that should be exported to file. * \return * \arg \c 0, Success. * \arg \c -1, Error occurred (check #harp_errno). */ LIBHARP_API int harp_export(const char *filename, const char *export_format, const harp_product *product) { file_format format; format = format_from_string(export_format); if (format == format_unknown) { harp_set_error(HARP_ERROR_INVALID_ARGUMENT, "unsupported export format '%s'", export_format); return -1; } switch (format) { case format_hdf4: #ifdef HAVE_HDF4 return harp_export_hdf4(filename, product); #else coda_set_error(HARP_ERROR_NO_HDF4_SUPPORT, NULL); return -1; #endif case format_hdf5: #ifdef HAVE_HDF5 return harp_export_hdf5(filename, product); #else coda_set_error(HARP_ERROR_NO_HDF5_SUPPORT, NULL); return -1; #endif case format_netcdf: return harp_export_netcdf(filename, product); default: assert(0); exit(1); } return 0; }
/** Get the product type version of a product file. * This function will return the format version number of a product. This version number is a rounded number and newer * versions of a format will always have a version number that is higher than that of older formats. * \param product Pointer to a product file handle. * \param version Pointer to the variable where the product version of the product type of the product will be stored. * \return * \arg \c 0, Success. * \arg \c -1, Error occurred (check #coda_errno). */ LIBCODA_API int coda_get_product_version(const coda_product *product, int *version) { if (product == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "product file argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (version == NULL) { coda_set_error(CODA_ERROR_INVALID_ARGUMENT, "version argument is NULL (%s:%u)", __FILE__, __LINE__); return -1; } if (product->product_definition != NULL) { *version = product->product_definition->version; } else { *version = -1; } return 0; }
coda_detection_rule *coda_detection_rule_new(void) { coda_detection_rule *detection_rule; detection_rule = malloc(sizeof(coda_detection_rule)); if (detection_rule == NULL) { coda_set_error(CODA_ERROR_OUT_OF_MEMORY, "out of memory (could not allocate %lu bytes) (%s:%u)", (long)sizeof(coda_detection_rule), __FILE__, __LINE__); return NULL; } detection_rule->num_entries = 0; detection_rule->entry = NULL; detection_rule->product_definition = NULL; return detection_rule; }
static coda_detection_node *detection_node_new(void) { coda_detection_node *node; node = malloc(sizeof(coda_detection_node)); if (node == NULL) { coda_set_error(CODA_ERROR_OUT_OF_MEMORY, "out of memory (could not allocate %lu bytes) (%s:%u)", (long)sizeof(coda_detection_node), __FILE__, __LINE__); return NULL; } node->path = NULL; node->expression = NULL; node->rule = NULL; node->num_subnodes = 0; node->subnode = NULL; return node; }