opj_codec_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT p_format)
{
    opj_codec_private_t *l_codec = 00;

    l_codec = (opj_codec_private_t*) opj_calloc(1, sizeof(opj_codec_private_t));
    if (!l_codec) {
        return 00;
    }

    l_codec->is_decompressor = 1;

    switch (p_format) {
    case OPJ_CODEC_J2K:
        l_codec->opj_dump_codec = (void (*)(void*, OPJ_INT32, FILE*)) j2k_dump;

        l_codec->opj_get_codec_info = (opj_codestream_info_v2_t* (*)(
                                           void*)) j2k_get_cstr_info;

        l_codec->opj_get_codec_index = (opj_codestream_index_t* (*)(
                                            void*)) j2k_get_cstr_index;

        l_codec->m_codec_data.m_decompression.opj_decode =
            (OPJ_BOOL(*)(void *,
                         struct opj_stream_private *,
                         opj_image_t*, struct opj_event_mgr *)) opj_j2k_decode;

        l_codec->m_codec_data.m_decompression.opj_end_decompress =
            (OPJ_BOOL(*)(void *,
                         struct opj_stream_private *,
                         struct opj_event_mgr *)) opj_j2k_end_decompress;

        l_codec->m_codec_data.m_decompression.opj_read_header =
            (OPJ_BOOL(*)(struct opj_stream_private *,
                         void *,
                         opj_image_t **,
                         struct opj_event_mgr *)) opj_j2k_read_header;

        l_codec->m_codec_data.m_decompression.opj_destroy =
            (void (*)(void *))opj_j2k_destroy;

        l_codec->m_codec_data.m_decompression.opj_setup_decoder =
            (void (*)(void *, opj_dparameters_t *)) opj_j2k_setup_decoder;

        l_codec->m_codec_data.m_decompression.opj_read_tile_header =
            (OPJ_BOOL(*)(void *,
                         OPJ_UINT32*,
                         OPJ_UINT32*,
                         OPJ_INT32*, OPJ_INT32*,
                         OPJ_INT32*, OPJ_INT32*,
                         OPJ_UINT32*,
                         OPJ_BOOL*,
                         struct opj_stream_private *,
                         struct opj_event_mgr *)) opj_j2k_read_tile_header;

        l_codec->m_codec_data.m_decompression.opj_decode_tile_data =
            (OPJ_BOOL(*)(void *,
                         OPJ_UINT32,
                         OPJ_BYTE*,
                         OPJ_UINT32,
                         struct opj_stream_private *,
                         struct opj_event_mgr *)) opj_j2k_decode_tile;

        l_codec->m_codec_data.m_decompression.opj_set_decode_area =
            (OPJ_BOOL(*)(void *,
                         opj_image_t*,
                         OPJ_INT32, OPJ_INT32, OPJ_INT32, OPJ_INT32,
                         struct opj_event_mgr *)) opj_j2k_set_decode_area;

        l_codec->m_codec_data.m_decompression.opj_get_decoded_tile =
            (OPJ_BOOL(*)(void *p_codec,
                         opj_stream_private_t *p_cio,
                         opj_image_t *p_image,
                         struct opj_event_mgr * p_manager,
                         OPJ_UINT32 tile_index)) opj_j2k_get_tile;

        l_codec->m_codec_data.m_decompression.opj_set_decoded_resolution_factor =
            (OPJ_BOOL(*)(void * p_codec,
                         OPJ_UINT32 res_factor,
                         struct opj_event_mgr * p_manager)) opj_j2k_set_decoded_resolution_factor;

        l_codec->m_codec_data.m_decompression.opj_set_decoded_components =
            (OPJ_BOOL(*)(void * p_codec,
                         OPJ_UINT32 numcomps,
                         const OPJ_UINT32 * comps_indices,
                         struct opj_event_mgr * p_manager)) opj_j2k_set_decoded_components;

        l_codec->opj_set_threads =
            (OPJ_BOOL(*)(void * p_codec, OPJ_UINT32 num_threads)) opj_j2k_set_threads;

        l_codec->m_codec = opj_j2k_create_decompress();

        if (! l_codec->m_codec) {
            opj_free(l_codec);
            return NULL;
        }

        break;

    case OPJ_CODEC_JP2:
        /* get a JP2 decoder handle */
        l_codec->opj_dump_codec = (void (*)(void*, OPJ_INT32, FILE*)) jp2_dump;

        l_codec->opj_get_codec_info = (opj_codestream_info_v2_t* (*)(
                                           void*)) jp2_get_cstr_info;

        l_codec->opj_get_codec_index = (opj_codestream_index_t* (*)(
                                            void*)) jp2_get_cstr_index;

        l_codec->m_codec_data.m_decompression.opj_decode =
            (OPJ_BOOL(*)(void *,
                         struct opj_stream_private *,
                         opj_image_t*,
                         struct opj_event_mgr *)) opj_jp2_decode;

        l_codec->m_codec_data.m_decompression.opj_end_decompress =
            (OPJ_BOOL(*)(void *,
                         struct opj_stream_private *,
                         struct opj_event_mgr *)) opj_jp2_end_decompress;

        l_codec->m_codec_data.m_decompression.opj_read_header =
            (OPJ_BOOL(*)(struct opj_stream_private *,
                         void *,
                         opj_image_t **,
                         struct opj_event_mgr *)) opj_jp2_read_header;

        l_codec->m_codec_data.m_decompression.opj_read_tile_header =
            (OPJ_BOOL(*)(void *,
                         OPJ_UINT32*,
                         OPJ_UINT32*,
                         OPJ_INT32*,
                         OPJ_INT32*,
                         OPJ_INT32 *,
                         OPJ_INT32 *,
                         OPJ_UINT32 *,
                         OPJ_BOOL *,
                         struct opj_stream_private *,
                         struct opj_event_mgr *)) opj_jp2_read_tile_header;

        l_codec->m_codec_data.m_decompression.opj_decode_tile_data =
            (OPJ_BOOL(*)(void *,
                         OPJ_UINT32, OPJ_BYTE*, OPJ_UINT32,
                         struct opj_stream_private *,
                         struct opj_event_mgr *)) opj_jp2_decode_tile;

        l_codec->m_codec_data.m_decompression.opj_destroy = (void (*)(
                    void *))opj_jp2_destroy;

        l_codec->m_codec_data.m_decompression.opj_setup_decoder =
            (void (*)(void *, opj_dparameters_t *)) opj_jp2_setup_decoder;

        l_codec->m_codec_data.m_decompression.opj_set_decode_area =
            (OPJ_BOOL(*)(void *,
                         opj_image_t*,
                         OPJ_INT32, OPJ_INT32, OPJ_INT32, OPJ_INT32,
                         struct opj_event_mgr *)) opj_jp2_set_decode_area;

        l_codec->m_codec_data.m_decompression.opj_get_decoded_tile =
            (OPJ_BOOL(*)(void *p_codec,
                         opj_stream_private_t *p_cio,
                         opj_image_t *p_image,
                         struct opj_event_mgr * p_manager,
                         OPJ_UINT32 tile_index)) opj_jp2_get_tile;

        l_codec->m_codec_data.m_decompression.opj_set_decoded_resolution_factor =
            (OPJ_BOOL(*)(void * p_codec,
                         OPJ_UINT32 res_factor,
                         opj_event_mgr_t * p_manager)) opj_jp2_set_decoded_resolution_factor;

        l_codec->m_codec_data.m_decompression.opj_set_decoded_components =
            (OPJ_BOOL(*)(void * p_codec,
                         OPJ_UINT32 numcomps,
                         const OPJ_UINT32 * comps_indices,
                         struct opj_event_mgr * p_manager)) opj_jp2_set_decoded_components;

        l_codec->opj_set_threads =
            (OPJ_BOOL(*)(void * p_codec, OPJ_UINT32 num_threads)) opj_jp2_set_threads;

        l_codec->m_codec = opj_jp2_create(OPJ_TRUE);

        if (! l_codec->m_codec) {
            opj_free(l_codec);
            return 00;
        }

        break;
    case OPJ_CODEC_UNKNOWN:
    case OPJ_CODEC_JPT:
    default:
        opj_free(l_codec);
        return 00;
    }

    opj_set_default_event_handler(&(l_codec->m_event_mgr));
    return (opj_codec_t*) l_codec;
}