/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * Copyright by the Board of Trustees of the University of Illinois.         *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF.  The full HDF copyright notice, including       *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF/releases/.  *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
   cdeflate.c - HDF gzip 'deflate' encoding I/O routines

   None of these routines are designed to be called by other users except
   for the modeling layer of the compression routines.
 */

/* General HDF includes */
#include "hdf_priv.h"

/* HDF compression includes */
#include "hcomp_priv.h" /* Internal definitions for compression */

/* Define the [default] size of the buffer to interact with the file */
#define DEFLATE_BUF_SIZE     4096
#define DEFLATE_TMP_BUF_SIZE 16384

/* functions to perform gzip encoding */
funclist_t cdeflate_funcs = {HCPcdeflate_stread,
                             HCPcdeflate_stwrite,
                             HCPcdeflate_seek,
                             HCPcdeflate_inquire,
                             HCPcdeflate_read,
                             HCPcdeflate_write,
                             HCPcdeflate_endaccess,
                             NULL,
                             NULL};

/* declaration of the functions provided in this module */
static int32 HCIcdeflate_init(compinfo_t *info);

/*--------------------------------------------------------------------------
 NAME
    HCIcdeflate_init -- Initialize a gzip 'deflate' compressed data element.

 USAGE
    int32 HCIcdeflate_init(info)
    compinfo_t *info;           IN: special element information

 RETURNS
    Returns SUCCEED or FAIL

 DESCRIPTION
    Common code called by HCIcdeflate_staccess and HCIcdeflate_seek
--------------------------------------------------------------------------*/
static int32
HCIcdeflate_init(compinfo_t *info)
{
    comp_coder_deflate_info_t *deflate_info; /* ptr to deflate info */

    if (Hseek(info->aid, 0, 0) == FAIL) /* seek to beginning of element */
        HRETURN_ERROR(DFE_SEEKERROR, FAIL);

    deflate_info = &(info->cinfo.coder_info.deflate_info);

    /* Initialize deflation state information */
    deflate_info->offset   = 0; /* start at the beginning of the data */
    deflate_info->acc_init = 0; /* second stage of initializing not performed */
    deflate_info->acc_mode = 0; /* init access mode to illegal value */

    /* initialize compression context */
    deflate_info->deflate_context.zalloc    = (alloc_func)Z_NULL;
    deflate_info->deflate_context.zfree     = (free_func)Z_NULL;
    deflate_info->deflate_context.opaque    = NULL;
    deflate_info->deflate_context.data_type = Z_BINARY;

    return SUCCEED;
} /* end HCIcdeflate_init() */

/*--------------------------------------------------------------------------
 NAME
    HCIcdeflate_decode -- Decode skipping Huffman compressed data into a buffer.

 USAGE
    int32 HCIcdeflate_decode(info,length,buf)
    compinfo_t *info;   IN: the info about the compressed element
    int32 length;       IN: number of bytes to read into the buffer
    uint8 *buf;         OUT: buffer to store the bytes read

 RETURNS
    Returns # of bytes decompressed or FAIL

 DESCRIPTION
    Common code called to decode gzip 'deflated' data from the file.
--------------------------------------------------------------------------*/
static int32
HCIcdeflate_decode(compinfo_t *info, int32 length, uint8 *buf)
{
    comp_coder_deflate_info_t *deflate_info; /* ptr to deflate info */
    int                        zstat;        /* inflate status */
    int32                      bytes_read;

    deflate_info = &(info->cinfo.coder_info.deflate_info);

    /* Set up the deflation buffers to point to the user's buffer to fill */
    deflate_info->deflate_context.next_out  = buf;
    deflate_info->deflate_context.avail_out = (uInt)length;
    while (deflate_info->deflate_context.avail_out > 0) {
        /* Get more bytes from the file, if we've run out */
        if (deflate_info->deflate_context.avail_in == 0) {
            int32 file_bytes;

            deflate_info->deflate_context.next_in = deflate_info->io_buf;
            if ((file_bytes = Hread(info->aid, DEFLATE_BUF_SIZE, deflate_info->deflate_context.next_in)) ==
                FAIL)
                HRETURN_ERROR(DFE_READERROR, FAIL);
            deflate_info->deflate_context.avail_in = (uInt)file_bytes;
        } /* end if */

        /* Read compressed data */
        zstat = inflate(&(deflate_info->deflate_context), Z_NO_FLUSH);

        /* break out if we've reached the end of the compressed data */
        if (zstat == Z_STREAM_END)
            break;

        /* break out if "inflate" returns reading errors */
        else if (zstat == Z_VERSION_ERROR) {
            HRETURN_ERROR(DFE_COMPVERSION, FAIL);
        }
        else if (zstat <= Z_ERRNO && zstat > Z_VERSION_ERROR) {
            HRETURN_ERROR(DFE_READCOMP, FAIL);
        }
    } /* end while */
    bytes_read = (int32)length - (int32)deflate_info->deflate_context.avail_out;
    deflate_info->offset += bytes_read;

    return bytes_read;
} /* end HCIcdeflate_decode() */

/*--------------------------------------------------------------------------
 NAME
    HCIcdeflate_encode -- Encode data from a buffer into gzip 'deflated'
                            compressed data

 USAGE
    int32 HCIcdeflate_encode(info,length,buf)
    compinfo_t *info;   IN: the info about the compressed element
    int32 length;       IN: number of bytes to store from the buffer
    const void *buf;    IN: buffer to encode

 RETURNS
    Returns SUCCEED or FAIL

 DESCRIPTION
    Common code called to encode gzip 'deflated' data into a file.
--------------------------------------------------------------------------*/
static int32
HCIcdeflate_encode(compinfo_t *info, int32 length, const void *buf)
{
    comp_coder_deflate_info_t *deflate_info; /* ptr to skipping Huffman info */

    deflate_info = &(info->cinfo.coder_info.deflate_info);

    /* Set up the deflation buffers to point to the user's buffer to empty */
    deflate_info->deflate_context.next_in  = (void *)buf;
    deflate_info->deflate_context.avail_in = (uInt)length;
    while (deflate_info->deflate_context.avail_in > 0 || deflate_info->deflate_context.avail_out == 0) {
        /* Write more bytes from the file, if we've filled our buffer */
        if (deflate_info->deflate_context.avail_out == 0) {
            if (deflate_info->deflate_context.next_out != NULL) {
                if (Hwrite(info->aid, DEFLATE_BUF_SIZE, deflate_info->io_buf) == FAIL)
                    HRETURN_ERROR(DFE_WRITEERROR, FAIL);
            }
            deflate_info->deflate_context.next_out  = deflate_info->io_buf;
            deflate_info->deflate_context.avail_out = DEFLATE_BUF_SIZE;
        } /* end if */

        /* break out if we've reached the end of the compressed data somehow */
        if (deflate(&(deflate_info->deflate_context), Z_NO_FLUSH) != Z_OK) {
            HRETURN_ERROR(DFE_CENCODE, FAIL);
        }
    }
    deflate_info->offset += length; /* incr. abs. offset into the file */

    return length;
} /* end HCIcdeflate_encode() */

/*--------------------------------------------------------------------------
 NAME
    HCIcdeflate_term -- Close down internal buffering for gzip 'deflate' encoding

 USAGE
    int32 HCIcdeflate_term(info,acc_mode)
    compinfo_t *info;   IN: the info about the compressed element
    int16  acc_mode;    IN: the access mode the data element was opened with

 RETURNS
    Returns SUCCEED or FAIL

 DESCRIPTION
    Common code called to flush gzip 'deflated' data into a file.

 GLOBAL VARIABLES
 COMMENTS, BUGS, ASSUMPTIONS
 EXAMPLES
 REVISION LOG
--------------------------------------------------------------------------*/
static int32
HCIcdeflate_term(compinfo_t *info, int16 acc_mode)
{
    comp_coder_deflate_info_t *deflate_info; /* ptr to deflation info */

    deflate_info = &(info->cinfo.coder_info.deflate_info);

    /* set flag to indicate second stage of initialization is finished */

    if (deflate_info->acc_init != 0) {
        if (acc_mode & DFACC_WRITE) { /* flush the "deflated" data to the file */
            intn status;

            do {
                /* Write more bytes from the file, if we've filled our buffer */
                if (deflate_info->deflate_context.avail_out == 0) {
                    if (Hwrite(info->aid, DEFLATE_BUF_SIZE, deflate_info->io_buf) == FAIL)
                        HRETURN_ERROR(DFE_WRITEERROR, FAIL);
                    deflate_info->deflate_context.next_out  = deflate_info->io_buf;
                    deflate_info->deflate_context.avail_out = DEFLATE_BUF_SIZE;
                } /* end if */

                status = deflate(&(deflate_info->deflate_context), Z_FINISH);
            } while (status == Z_OK || deflate_info->deflate_context.avail_out == 0);
            if (status != Z_STREAM_END)
                HRETURN_ERROR(DFE_CENCODE, FAIL);
            if (deflate_info->deflate_context.avail_out < DEFLATE_BUF_SIZE)
                if (Hwrite(info->aid, (int32)(DEFLATE_BUF_SIZE - deflate_info->deflate_context.avail_out),
                           deflate_info->io_buf) == FAIL)
                    HRETURN_ERROR(DFE_WRITEERROR, FAIL);

            /* Close down the deflation buffer */
            if (deflateEnd(&(deflate_info->deflate_context)) != Z_OK)
                HRETURN_ERROR(DFE_CTERM, FAIL);
        }      /* end if */
        else { /* finish up any inflated data */
            /* Close down the inflation buffer */
            if (inflateEnd(&(deflate_info->deflate_context)) != Z_OK)
                HRETURN_ERROR(DFE_CTERM, FAIL);
        } /* end else */
    }     /* end if */

    /* Reset parameters */
    deflate_info->offset   = 0; /* start at the beginning of the data */
    deflate_info->acc_init = 0; /* second stage of initializing not performed */
    deflate_info->acc_mode = 0; /* init access mode to illegal value */

    return SUCCEED;
} /* end HCIcdeflate_term() */

/*--------------------------------------------------------------------------
 NAME
    HCIcdeflate_staccess -- Start accessing a gzip 'deflate' compressed data element.

 USAGE
    int32 HCIcdeflate_staccess(access_rec, access)
    accrec_t *access_rec;   IN: the access record of the data element
    int16 access;           IN: the type of access wanted

 RETURNS
    Returns SUCCEED or FAIL

 DESCRIPTION
    Common code called by HCIcdeflate_stread and HCIcdeflate_stwrite
--------------------------------------------------------------------------*/
static int32
HCIcdeflate_staccess(accrec_t *access_rec, int16 acc_mode)
{
    compinfo_t                *info;         /* special element information */
    comp_coder_deflate_info_t *deflate_info; /* ptr to deflate info */

    info         = (compinfo_t *)access_rec->special_info;
    deflate_info = &(info->cinfo.coder_info.deflate_info);

    /* need to check for not writing, as opposed to read access */
    /* because of the way the access works */
    if (!(acc_mode & DFACC_WRITE)) {
        info->aid = Hstartread(access_rec->file_id, DFTAG_COMPRESSED, info->comp_ref);
    } /* end if */
    else {
        info->aid = Hstartaccess(access_rec->file_id, DFTAG_COMPRESSED, info->comp_ref,
                                 DFACC_RDWR | DFACC_APPENDABLE);
    } /* end else */
    if (info->aid == FAIL)
        HRETURN_ERROR(DFE_DENIED, FAIL);

    /* Make certain we can append to the data when writing */
    if ((acc_mode & DFACC_WRITE) && Happendable(info->aid) == FAIL)
        HRETURN_ERROR(DFE_DENIED, FAIL);

    /* initialize the common deflate coding info */
    if (HCIcdeflate_init(info) == FAIL)
        HRETURN_ERROR(DFE_CODER, FAIL);

    /* Allocate compression I/O buffer */
    if ((deflate_info->io_buf = malloc(DEFLATE_BUF_SIZE)) == NULL)
        HRETURN_ERROR(DFE_NOSPACE, FAIL);

    return SUCCEED;
} /* end HCIcdeflate_staccess() */

/*--------------------------------------------------------------------------
 NAME
    HCIcdeflate_staccess2 -- 2nd half of start accessing a gzip 'deflate'
                            compressed data element.

 USAGE
    int32 HCIcdeflate_staccess2(access_rec, access)
    accrec_t *access_rec;   IN: the access record of the data element
    int16 access;           IN: the type of access wanted

 RETURNS
    Returns SUCCEED or FAIL

 DESCRIPTION
    Common code called by HCIcdeflate_stread and HCIcdeflate_stwrite
--------------------------------------------------------------------------*/
static int32
HCIcdeflate_staccess2(accrec_t *access_rec, int16 acc_mode)
{
    compinfo_t                *info;         /* special element information */
    comp_coder_deflate_info_t *deflate_info; /* ptr to deflate info */

    info         = (compinfo_t *)access_rec->special_info;
    deflate_info = &(info->cinfo.coder_info.deflate_info);

    /* Initialize the gzip library */
    if (acc_mode & DFACC_WRITE) {
        if (deflateInit(&(deflate_info->deflate_context), deflate_info->deflate_level) != Z_OK)
            HRETURN_ERROR(DFE_CINIT, FAIL);

        /* set access mode */
        deflate_info->acc_mode = DFACC_WRITE;

        /* force I/O with the file at first */
        deflate_info->deflate_context.next_out  = NULL;
        deflate_info->deflate_context.avail_out = 0;
    } /* end if */
    else {
        if (inflateInit(&(deflate_info->deflate_context)) != Z_OK)
            HRETURN_ERROR(DFE_CINIT, FAIL);

        /* set access mode */
        deflate_info->acc_mode = DFACC_READ;

        /* force I/O with the file at first */
        deflate_info->deflate_context.avail_in = 0;
    } /* end else */

    /* set flag to indicate second stage of initialization is finished */
    deflate_info->acc_init = acc_mode;

    return SUCCEED;
} /* end HCIcdeflate_staccess2() */

/*--------------------------------------------------------------------------
 NAME
    HCPcdeflate_stread -- start read access for compressed file

 USAGE
    int32 HCPcdeflate_stread(access_rec)
    accrec_t *access_rec;   IN: the access record of the data element

 RETURNS
    Returns SUCCEED or FAIL

 DESCRIPTION
    Start read access on a compressed data element using the deflate scheme.
--------------------------------------------------------------------------*/
int32
HCPcdeflate_stread(accrec_t *access_rec)
{
    if (HCIcdeflate_staccess(access_rec, DFACC_READ) == FAIL)
        HRETURN_ERROR(DFE_CINIT, FAIL);

    return SUCCEED;
} /* HCPcdeflate_stread() */

/*--------------------------------------------------------------------------
 NAME
    HCPcdeflate_stwrite -- start write access for compressed file

 USAGE
    int32 HCPcdeflate_stwrite(access_rec)
    accrec_t *access_rec;   IN: the access record of the data element

 RETURNS
    Returns SUCCEED or FAIL

 DESCRIPTION
    Start write access on a compressed data element using the deflate scheme.
--------------------------------------------------------------------------*/
int32
HCPcdeflate_stwrite(accrec_t *access_rec)
{
    if (HCIcdeflate_staccess(access_rec, DFACC_WRITE) == FAIL)
        HRETURN_ERROR(DFE_CINIT, FAIL);

    return SUCCEED;
} /* HCPcdeflate_stwrite() */

/*--------------------------------------------------------------------------
 NAME
    HCPcdeflate_seek -- Seek to offset within the data element

 USAGE
    int32 HCPcdeflate_seek(access_rec,offset,origin)
    accrec_t *access_rec;   IN: the access record of the data element
    int32 offset;       IN: the offset in bytes from the origin specified
    intn origin;        IN: the origin to seek from [UNUSED!]

 RETURNS
    Returns SUCCEED or FAIL

 DESCRIPTION
    Seek to a position with a compressed data element.  The 'origin'
    calculations have been taken care of at a higher level, it is an
    un-used parameter.  The 'offset' is used as an absolute offset
    because of this.
--------------------------------------------------------------------------*/
int32
HCPcdeflate_seek(accrec_t *access_rec, int32 offset, int origin)
{
    compinfo_t                *info;             /* special element information */
    comp_coder_deflate_info_t *deflate_info;     /* ptr to gzip 'deflate' info */
    uint8                     *tmp_buf   = NULL; /* temporary buffer */
    int32                      ret_value = SUCCEED;

    (void)origin;

    info         = (compinfo_t *)access_rec->special_info;
    deflate_info = &(info->cinfo.coder_info.deflate_info);

    /* Check if second stage of initialization has been performed */
    if (deflate_info->acc_init == 0) {
        if (HCIcdeflate_staccess2(access_rec, DFACC_READ) == FAIL)
            HGOTO_ERROR(DFE_CINIT, FAIL);
    }

    if (offset < deflate_info->offset) {

        /* need to seek from the beginning */

        /* Terminate the previous method of access */
        if (HCIcdeflate_term(info, deflate_info->acc_mode) == FAIL)
            HGOTO_ERROR(DFE_CTERM, FAIL);

        /* Restart access */
        if (HCIcdeflate_staccess2(access_rec, DFACC_READ) == FAIL)
            HGOTO_ERROR(DFE_CINIT, FAIL);

        /* Go back to the beginning of the data-stream */
        if (Hseek(info->aid, 0, 0) == FAIL)
            HGOTO_ERROR(DFE_SEEKERROR, FAIL);
    }

    /* Allocate a temporary buffer for decompression */
    if ((tmp_buf = (uint8 *)malloc(sizeof(uint8) * DEFLATE_TMP_BUF_SIZE)) == NULL)
        HGOTO_ERROR(DFE_NOSPACE, FAIL);

    while (deflate_info->offset + DEFLATE_TMP_BUF_SIZE < offset) {
        /* grab chunks */
        if (HCIcdeflate_decode(info, DEFLATE_TMP_BUF_SIZE, tmp_buf) == FAIL) {
            HGOTO_ERROR(DFE_CDECODE, FAIL);
        }
    }
    if (deflate_info->offset < offset) {
        /* grab the last chunk */
        if (HCIcdeflate_decode(info, offset - deflate_info->offset, tmp_buf) == FAIL) {
            HGOTO_ERROR(DFE_CDECODE, FAIL);
        }
    }

done:
    free(tmp_buf);

    return ret_value;
} /* HCPcdeflate_seek() */

/*--------------------------------------------------------------------------
 NAME
    HCPcdeflate_read -- Read in a portion of data from a compressed data element.

 USAGE
    int32 HCPcdeflate_read(access_rec,length,data)
    accrec_t *access_rec;   IN: the access record of the data element
    int32 length;           IN: the number of bytes to read
    void * data;             OUT: the buffer to place the bytes read

 RETURNS
    Returns the number of bytes read or FAIL

 DESCRIPTION
    Read in a number of bytes from the deflate compressed data element.
--------------------------------------------------------------------------*/
int32
HCPcdeflate_read(accrec_t *access_rec, int32 length, void *data)
{
    compinfo_t                *info;         /* special element information */
    comp_coder_deflate_info_t *deflate_info; /* ptr to gzip 'deflate' info */

    info         = (compinfo_t *)access_rec->special_info;
    deflate_info = &(info->cinfo.coder_info.deflate_info);

    /* Check if second stage of initialization has been performed */
    if (deflate_info->acc_init != DFACC_READ) {
        /* Terminate the previous method of access */
        if (HCIcdeflate_term(info, deflate_info->acc_mode) == FAIL)
            HRETURN_ERROR(DFE_CTERM, FAIL);

        /* Restart access */
        if (HCIcdeflate_staccess2(access_rec, DFACC_READ) == FAIL)
            HRETURN_ERROR(DFE_CINIT, FAIL);

        /* Go back to the beginning of the data-stream */
        if (Hseek(info->aid, 0, 0) == FAIL)
            HRETURN_ERROR(DFE_SEEKERROR, FAIL);
    } /* end if */

    if ((length = HCIcdeflate_decode(info, length, data)) == FAIL)
        HRETURN_ERROR(DFE_CDECODE, FAIL);

    return length;
} /* HCPcdeflate_read() */

/*--------------------------------------------------------------------------
 NAME
    HCPcdeflate_write -- Write out a portion of data from a compressed data element.

 USAGE
    int32 HCPcdeflate_write(access_rec,length,data)
    accrec_t *access_rec;   IN: the access record of the data element
    int32 length;           IN: the number of bytes to write
    void * data;             IN: the buffer to retrieve the bytes written

 RETURNS
    Returns the number of bytes written or FAIL

 DESCRIPTION
    Write out a number of bytes to the deflate compressed data element.
--------------------------------------------------------------------------*/
int32
HCPcdeflate_write(accrec_t *access_rec, int32 length, const void *data)
{
    compinfo_t                *info;         /* special element information */
    comp_coder_deflate_info_t *deflate_info; /* ptr to skipping Huffman info */

    info         = (compinfo_t *)access_rec->special_info;
    deflate_info = &(info->cinfo.coder_info.deflate_info);

    /* Don't allow random write in a dataset unless: */
    /*  1 - append onto the end */
    /*  2 - start at the beginning and rewrite (at least) the whole dataset */
    if ((info->length != deflate_info->offset) && (deflate_info->offset != 0 || length < info->length))
        HRETURN_ERROR(DFE_UNSUPPORTED, FAIL);

    /* Check if second stage of initialization has been performed */
    if (deflate_info->acc_init != DFACC_WRITE) {
        /* Terminate the previous method of access */
        if (HCIcdeflate_term(info, deflate_info->acc_init) == FAIL)
            HRETURN_ERROR(DFE_CTERM, FAIL);

        /* Restart access */
        if (HCIcdeflate_staccess2(access_rec, DFACC_WRITE) == FAIL)
            HRETURN_ERROR(DFE_CINIT, FAIL);

        /* Go back to the beginning of the data-stream */
        if (Hseek(info->aid, 0, 0) == FAIL)
            HRETURN_ERROR(DFE_SEEKERROR, FAIL);
    } /* end if */

    if ((length = HCIcdeflate_encode(info, length, data)) == FAIL)
        HRETURN_ERROR(DFE_CENCODE, FAIL);

    return length;
} /* HCPcdeflate_write() */

/*--------------------------------------------------------------------------
 NAME
    HCPcdeflate_inquire -- Inquire information about the access record and data element.

 USAGE
    int32 HCPcdeflate_inquire(access_rec,pfile_id,ptag,pref,plength,poffset,pposn,
            paccess,pspecial)
    accrec_t *access_rec;   IN: the access record of the data element
    int32 *pfile_id;        OUT: ptr to file id
    uint16 *ptag;           OUT: ptr to tag of information
    uint16 *pref;           OUT: ptr to ref of information
    int32 *plength;         OUT: ptr to length of data element
    int32 *poffset;         OUT: ptr to offset of data element
    int32 *pposn;           OUT: ptr to position of access in element
    int16 *paccess;         OUT: ptr to access mode
    int16 *pspecial;        OUT: ptr to special code

 RETURNS
    Returns SUCCEED or FAIL

 DESCRIPTION
    Inquire information about the access record and data element.
    [Currently a NOP].
--------------------------------------------------------------------------*/
int32
HCPcdeflate_inquire(accrec_t *access_rec, int32 *pfile_id, uint16 *ptag, uint16 *pref, int32 *plength,
                    int32 *poffset, int32 *pposn, int16 *paccess, int16 *pspecial)
{
    (void)access_rec;
    (void)pfile_id;
    (void)ptag;
    (void)pref;
    (void)plength;
    (void)poffset;
    (void)pposn;
    (void)paccess;
    (void)pspecial;

    return SUCCEED;
} /* HCPcdeflate_inquire() */

/*--------------------------------------------------------------------------
 NAME
    HCPcdeflate_endaccess -- Close the compressed data element

 USAGE
    int32 HCPcdeflate_endaccess(access_rec)
    accrec_t *access_rec;   IN: the access record of the data element

 RETURNS
    Returns SUCCEED or FAIL

 DESCRIPTION
    Close the compressed data element and free encoding info.
--------------------------------------------------------------------------*/
intn
HCPcdeflate_endaccess(accrec_t *access_rec)
{
    compinfo_t                *info;         /* special element information */
    comp_coder_deflate_info_t *deflate_info; /* ptr to gzip 'deflate' info */

    info         = (compinfo_t *)access_rec->special_info;
    deflate_info = &(info->cinfo.coder_info.deflate_info);

    /* flush out buffer */
    if (HCIcdeflate_term(info, deflate_info->acc_mode) == FAIL)
        HRETURN_ERROR(DFE_CTERM, FAIL);

    /* Get rid of the I/O buffer */
    free(deflate_info->io_buf);

    /* close the compressed data AID */
    if (Hendaccess(info->aid) == FAIL)
        HRETURN_ERROR(DFE_CANTCLOSE, FAIL);

    return SUCCEED;
} /* HCPcdeflate_endaccess() */
