/*
 * Copyright (c) 2018-2020, Intel Corporation
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of Intel Corporation nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef CH_COMMON_H_
#define CH_COMMON_H_

#include "hs_common.h"

#include <stdlib.h>

/**
 * @file
 * @brief The Chimera common API definition.
 *
 * Chimera is a hybrid of Hyperscan and PCRE.
 *
 * This header contains functions available to both the Chimera compiler and
 * runtime.
 */

#ifdef __cplusplus
extern "C"
{
#endif

struct ch_database;

/**
 * A Chimera pattern database.
 *
 * Generated by one of the Chimera compiler functions:
 *  - @ref ch_compile()
 *  - @ref ch_compile_multi()
 *  - @ref ch_compile_ext_multi()
 */
typedef struct ch_database ch_database_t;

/**
 * A type for errors returned by Chimera functions.
 */
typedef int ch_error_t;

/**
 * Free a compiled pattern database.
 *
 * The free callback set by @ref ch_set_allocator()) will be used by this
 * function.
 *
 * @param db
 *      A compiled pattern database. NULL may also be safely provided, in which
 *      case the function does nothing.
 *
 * @return
 *      @ref CH_SUCCESS on success, other values on failure.
 */
ch_error_t HS_CDECL ch_free_database(ch_database_t *db);

/**
 * Utility function for identifying this release version.
 *
 * @return
 *      A string containing the version number of this release build and the
 *      date of the build. It is allocated statically, so it does not need to
 *      be freed by the caller.
 */
const char * HS_CDECL ch_version(void);

/**
 * Returns the size of the given database.
 *
 * @param database
 *      Pointer to compiled expression database.
 *
 * @param database_size
 *      On success, the size of the compiled database in bytes is placed in this
 *      parameter.
 *
 * @return
 *      @ref CH_SUCCESS on success, other values on failure.
 */
ch_error_t HS_CDECL ch_database_size(const ch_database_t *database,
                                     size_t *database_size);

/**
 * Utility function providing information about a database.
 *
 * @param database
 *      Pointer to a compiled database.
 *
 * @param info
 *      On success, a string containing the version and platform information for
 *      the supplied database is placed in the parameter. The string is
 *      allocated using the allocator supplied in @ref hs_set_allocator()
 *      (or malloc() if no allocator was set) and should be freed by the caller.
 *
 * @return
 *      @ref CH_SUCCESS on success, other values on failure.
 */
ch_error_t HS_CDECL ch_database_info(const ch_database_t *database,
                                     char **info);

/**
 * The type of the callback function that will be used by Chimera to allocate
 * more memory at runtime as required.
 *
 * If Chimera is to be used in a multi-threaded, or similarly concurrent
 * environment, the allocation function will need to be re-entrant, or
 * similarly safe for concurrent use.
 *
 * @param size
 *      The number of bytes to allocate.
 * @return
 *      A pointer to the region of memory allocated, or NULL on error.
 */
typedef void *(HS_CDECL *ch_alloc_t)(size_t size);

/**
 * The type of the callback function that will be used by Chimera to free
 * memory regions previously allocated using the @ref ch_alloc_t function.
 *
 * @param ptr
 *      The region of memory to be freed.
 */
typedef void (HS_CDECL *ch_free_t)(void *ptr);

/**
 * Set the allocate and free functions used by Chimera for allocating
 * memory at runtime for stream state, scratch space, database bytecode,
 * and various other data structure returned by the Chimera API.
 *
 * The function is equivalent to calling @ref ch_set_scratch_allocator(),
 * @ref ch_set_database_allocator() and
 * @ref ch_set_misc_allocator() with the provided parameters.
 *
 * This call will override any previous allocators that have been set.
 *
 * Note: there is no way to change the allocator used for temporary objects
 * created during the various compile calls (@ref ch_compile() and @ref
 * ch_compile_multi()).
 *
 * @param alloc_func
 *      A callback function pointer that allocates memory. This function must
 *      return memory suitably aligned for the largest representable data type
 *      on this platform.
 *
 * @param free_func
 *      A callback function pointer that frees allocated memory.
 *
 * @return
 *      @ref CH_SUCCESS on success, other values on failure.
 */
ch_error_t HS_CDECL ch_set_allocator(ch_alloc_t alloc_func,
                                     ch_free_t free_func);

/**
 * Set the allocate and free functions used by Chimera for allocating memory
 * for database bytecode produced by the compile calls (@ref ch_compile() and @ref
 * ch_compile_multi()).
 *
 * If no database allocation functions are set, or if NULL is used in place of
 * both parameters, then memory allocation will default to standard methods
 * (such as the system malloc() and free() calls).
 *
 * This call will override any previous database allocators that have been set.
 *
 * Note: the database allocator may also be set by calling @ref
 * ch_set_allocator().
 *
 * Note: there is no way to change how temporary objects created during the
 * various compile calls (@ref ch_compile() and @ref ch_compile_multi()) are
 * allocated.
 *
 * @param alloc_func
 *      A callback function pointer that allocates memory. This function must
 *      return memory suitably aligned for the largest representable data type
 *      on this platform.
 *
 * @param free_func
 *      A callback function pointer that frees allocated memory.
 *
 * @return
 *      @ref HS_SUCCESS on success, other values on failure.
 */
ch_error_t HS_CDECL ch_set_database_allocator(ch_alloc_t alloc_func,
                                              ch_free_t free_func);

/**
 * Set the allocate and free functions used by Chimera for allocating memory
 * for items returned by the Chimera API such as @ref ch_compile_error_t.
 *
 * If no misc allocation functions are set, or if NULL is used in place of both
 * parameters, then memory allocation will default to standard methods (such as
 * the system malloc() and free() calls).
 *
 * This call will override any previous misc allocators that have been set.
 *
 * Note: the misc allocator may also be set by calling @ref ch_set_allocator().
 *
 * @param alloc_func
 *      A callback function pointer that allocates memory. This function must
 *      return memory suitably aligned for the largest representable data type
 *      on this platform.
 *
 * @param free_func
 *      A callback function pointer that frees allocated memory.
 *
 * @return
 *      @ref CH_SUCCESS on success, other values on failure.
 */
ch_error_t HS_CDECL ch_set_misc_allocator(ch_alloc_t alloc_func,
                                          ch_free_t free_func);

/**
 * Set the allocate and free functions used by Chimera for allocating memory
 * for scratch space by @ref ch_alloc_scratch() and @ref ch_clone_scratch().
 *
 * If no scratch allocation functions are set, or if NULL is used in place of
 * both parameters, then memory allocation will default to standard methods
 * (such as the system malloc() and free() calls).
 *
 * This call will override any previous scratch allocators that have been set.
 *
 * Note: the scratch allocator may also be set by calling @ref
 * ch_set_allocator().
 *
 * @param alloc_func
 *      A callback function pointer that allocates memory. This function must
 *      return memory suitably aligned for the largest representable data type
 *      on this platform.
 *
 * @param free_func
 *      A callback function pointer that frees allocated memory.
 *
 * @return
 *      @ref CH_SUCCESS on success, other values on failure.
 */
ch_error_t HS_CDECL ch_set_scratch_allocator(ch_alloc_t alloc_func,
                                             ch_free_t free_func);

/**
 * @defgroup CH_ERROR ch_error_t values
 *
 * @{
 */

/**
 * The engine completed normally.
 */
#define CH_SUCCESS              0

/**
 * A parameter passed to this function was invalid.
 */
#define CH_INVALID              (-1)

/**
 * A memory allocation failed.
 */
#define CH_NOMEM                (-2)

/**
 * The engine was terminated by callback.
 *
 * This return value indicates that the target buffer was partially scanned,
 * but that the callback function requested that scanning cease after a match
 * was located.
 */
#define CH_SCAN_TERMINATED      (-3)

/**
 * The pattern compiler failed, and the @ref ch_compile_error_t should be
 * inspected for more detail.
 */
#define CH_COMPILER_ERROR       (-4)

/**
 * The given database was built for a different version of the Chimera matcher.
 */
#define CH_DB_VERSION_ERROR     (-5)

/**
 * The given database was built for a different platform (i.e., CPU type).
 */
#define CH_DB_PLATFORM_ERROR    (-6)

/**
 * The given database was built for a different mode of operation.  This error
 * is returned when streaming calls are used with a non-streaming database and
 * vice versa.
 */
#define CH_DB_MODE_ERROR        (-7)

/**
 * A parameter passed to this function was not correctly aligned.
 */
#define CH_BAD_ALIGN            (-8)

/**
 * The memory allocator did not correctly return memory suitably aligned for
 * the largest representable data type on this platform.
 */
#define CH_BAD_ALLOC            (-9)

/**
 * The scratch region was already in use.
 *
 * This error is returned when Chimera is able to detect that the scratch
 * region given is already in use by another Chimera API call.
 *
 * A separate scratch region, allocated with @ref ch_alloc_scratch() or @ref
 * ch_clone_scratch(), is required for every concurrent caller of the Chimera
 * API.
 *
 * For example, this error might be returned when @ref ch_scan() has been
 * called inside a callback delivered by a currently-executing @ref ch_scan()
 * call using the same scratch region.
 *
 * Note: Not all concurrent uses of scratch regions may be detected. This error
 * is intended as a best-effort debugging tool, not a guarantee.
 */
#define CH_SCRATCH_IN_USE       (-10)

/**
 * Unexpected internal error from Hyperscan.
 *
 * This error indicates that there was unexpected matching behaviors from
 * Hyperscan. This could be related to invalid usage of scratch space or
 * invalid memory operations by users.
 *
 */
#define CH_UNKNOWN_HS_ERROR     (-13)

/**
 * Returned when pcre_exec (called for some expressions internally from @ref
 * ch_scan) failed due to a fatal error.
 */
#define CH_FAIL_INTERNAL        (-32)

/** @} */

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* CH_COMMON_H_ */
