Beispiel #1
0
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;
}
Beispiel #2
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);
}
Beispiel #3
0
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;
}
Beispiel #4
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;
}
Beispiel #5
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;
}
Beispiel #6
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;
}
Beispiel #7
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;
}
Beispiel #8
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;
}
Beispiel #9
0
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;
}
Beispiel #10
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;
}
Beispiel #11
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;
}
Beispiel #12
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;
}
Beispiel #13
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);
}
Beispiel #14
0
/** 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;
}
Beispiel #15
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;
}
Beispiel #16
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;
}
Beispiel #17
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;
}
Beispiel #18
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;
}
Beispiel #19
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;
}
Beispiel #20
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;
}
Beispiel #21
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;
}
Beispiel #22
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;
}
Beispiel #23
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;
}
Beispiel #24
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;
}
Beispiel #25
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;
}
Beispiel #26
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;
}
Beispiel #27
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;
}
Beispiel #28
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;
}
Beispiel #29
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;
}
Beispiel #30
0
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;
}