/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by  The HDF Group and                                           *
 * The Board of Trustees of the University of Illinois.                      *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of H4H5TOOLS. The full H4H5TOOLS 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. The copyright notice can also be found     *
 * at https://www.hdfgroup.org/licenses.  If you do not have access to       *
 * either file, you may request a copy from help@hdfgroup.org.               *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/******************************************************************************

    Description: 

1. h4toh5 converter library 

See HDF4 to HDF5 mapping specification at
(https://support.hdfgroup.org/products/hdf5_tools/h4toh5/) for the default mapping 
from HDF4 object to HDF5 object.
 
The whole converter library includes 14 files, 

five header files:

     h4toh5.h 
     (all public h4toh5 APIs, needed for user who used h4toh5 library)

     h4toh5util.h(constants, utility and internal functions)

     h4toh5main.h(semi-public functions for all .c files)

     H4TOH5Ipublic.h(public header file copied and modified from HDF5 ID functions,users donot need to use this header file)

     H4TOH5Iprivate.h(private header file copied and modified from HDF5 ID functions,users should *NOT* use this header file)

nine C files:

     h4toh5util.c(utility and internal functions)
     h4toh5main.c(H4toH5open and h4toh5close functions)
     h4toh5sds.c(h4toh5sds,h4toh5alldimscale and h4toh5onedimscale functions)
     H4toH5image.c(H4toH5image function)
     h4toh5vdata.c(h4toh5vdata function)
     h4toh5vgroup.c(h4toh5basvgroup and h4toh5advgroup functions)
     h4toh5pal.c(h4toh5pal functions)
     h4toh5anno.c(h4toh5anno functions)
     H4TOH5I.c(function to deal with IDs *)

2. this file 

The API that convert an HDF4 Image into an HDF5 dataset.
Author:  Kent Yang(myang6@hdfgroup.org)
 

*****************************************************************************/

#include "h4toh5main.h"

/*-------------------------------------------------------------------------
 * Function:    gr_tranattrs
 *
 * Purpose:     translate attributes of Image object into HDF5 dataset
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
 
 sri_id: RI identifier
 sh5_dset: hdf5 dataset
 snum_grattrs: number of attribute
 check_gloflag: flag to check whether this attribute belongs
 to gr interface.
 attr_flag: Check to identify how the attributes are generated
 h4toh5id: h4toh5 identifier
 Out:                   
 *-------------------------------------------------------------------------
 */ 

int gr_tranattrs(hid_t h4toh5id,
         int32 sri_id, 
         hid_t sh5_dset,
         int snum_grattrs,
         int check_gloflag,
         int attr_flag)
{
        
    char            sgratrr_name[2*H4H5_MAX_NC_NAME]; /* image attribute name */
    char            grglo[H4H5_MAX_NC_NAME];/* GR interface attribute name */
    char*           grrepattr_name; /* GR attribute name */
    int32           count_sgradata; /* number of image attribute data */
    uint32      temp_countadata; /* temporary variable to store image attribute data */
    int32           sgr_atype; /* image attribute type */
    size_t      sh4_amemsize; /* the size of image attribute data type in memory */
    size_t      sh4_asize;/* the size of image attribute data type in disk */

    hid_t           sh5a_sid; /* data space id of image attribute */
    hid_t           sh5a_id; /* image attribute id */
    hid_t           sh5_atype; /* image attribute data type(in disk) */
    hid_t           sh5_amemtype;/* image attribute data type(in memory) */
    hid_t           sh5str_type; /* image attribute data type(in disk) with the HDF5 
                    string format */
    hid_t           sh5str_memtype; /* image attribute data type(in memory) with the 
                         HDF5 string format */
    hsize_t     sh5dims[1]; /* the size of each dimension of the image */
    void*           sgr_adata;/* data buffer to store the attribute */
    herr_t      sret; /* the temporary variable to check the return status of
                 HDF5 interfaces. */
    int             i; /* a temporary variable to be index of "for" loop */
    h4toh5id_t *dt; /* pointer to h4toh5id struct */

    dt = H4TOH5I_object(h4toh5id);
 
    for (i =0;i <snum_grattrs;i++) {
            
        /* obtain attribute information */
        if (GRattrinfo(sri_id,i,sgratrr_name,&sgr_atype,&count_sgradata)==FAIL){    
            H4toH5error_set(dt,2,"cannot obtain image attribute information",
                                 __FILE__,__LINE__);
            return FAIL;
        }
         
        /*convert datatype for attribute. */

        if(h4type_to_h5type(h4toh5id,sgr_atype,&sh5_amemtype,&sh4_amemsize,
            &sh4_asize,&sh5_atype)==FAIL){
            H4toH5error_set(dt,5,"cannot convert hdf4 datatype into hdf5 datatype",
                                 __FILE__,__LINE__);
            return FAIL;
        }

        sgr_adata = malloc(sh4_amemsize*count_sgradata);
        if(sgr_adata == NULL) {
            H4toH5error_set(dt,1,"cannot allocate memory for GR attribute data",
                                 __FILE__,__LINE__);
            return FAIL;
        }

        if(GRgetattr(sri_id,i,(VOIDP)sgr_adata)==FAIL){
            H4toH5error_set(dt,5,"cannot get GR attribute data",
                                 __FILE__,__LINE__);
            free(sgr_adata);
            return FAIL;
        }
    
        /* if attribute doesn't have name, a default name is set. */
        if(sgratrr_name[0] == '\0') {
            grrepattr_name = trans_obj_name(h4toh5id,DFTAG_RIG,i);
            strcpy(sgratrr_name,grrepattr_name);
            free(grrepattr_name);
        }

        /* if the GR attribute is a file attribute. */
        if(check_gloflag == 1 && (attr_flag == H425_OSPEC_ALLATTRS || attr_flag == H425_OSPEC_NO_PREDEF_ATTRS)){
            strcpy(grglo,GLOIMAGE);
            strcat(sgratrr_name,"_");
            strcat(sgratrr_name,grglo);
        }
        /* now do attribute-transferring.
             1. deal with string data type
             2. set attribute space.
             3. get attribute name, set property list. */
                     
        if (sh5_atype == H5T_STRING) {

            sh5a_sid = H5Screate(H5S_SCALAR);
            if (sh5a_sid < 0) {
                H4toH5error_set(dt,3,"cannot create attribute space for image",
                         __FILE__,__LINE__);
                 free(sgr_adata);
                return FAIL;
            }

            temp_countadata = count_sgradata;
            H425_CHECK_OVERFLOW(temp_countadata,uint32,size_t);
            if ((sh5str_type = mkstr(h4toh5id,(size_t)temp_countadata*sh4_asize,
                         H5T_STR_NULLTERM))<0){
                H4toH5error_set(dt,3,"cannot make HDF5 string for image attribute ",
                         __FILE__,__LINE__);
                 free(sgr_adata);
                H5Sclose(sh5a_sid);
                return FAIL;
            }

            if ((sh5str_memtype = mkstr(h4toh5id,count_sgradata*sh4_amemsize,
                    H5T_STR_NULLTERM))<0){
                H4toH5error_set(dt,3,"cannot create attribute space for IMAGE",
                         __FILE__,__LINE__);
                 free(sgr_adata);
                H5Sclose(sh5a_sid);
                return FAIL;
            }

            sh5a_id = H5Acreate_safe(h4toh5id,sh5_dset,sgratrr_name,sh5str_type,sh5a_sid,
                H5P_DEFAULT);
            if (sh5a_id <0) {
                if (transattrs_split(h4toh5id, sh5_dset, sgratrr_name, sh5a_sid, sgr_adata, count_sgradata) < 0) {
                    H4toH5error_set(dt,3,"cannot obtain attribute id",
                             __FILE__,__LINE__);
                    H5Sclose(sh5a_sid);
                    free(sgr_adata);
                    return FAIL;
                }
            }
            else if (H5Awrite(sh5a_id,sh5str_memtype,(void *)sgr_adata) < 0) {
                H4toH5error_set(dt,3,"cannot write attribute data",
                         __FILE__,__LINE__);
                H5Sclose(sh5a_sid);
                H5Aclose(sh5a_id);
                 free(sgr_adata);
                return FAIL;
            }
        }
     
        else {
            
            if (!H4toH5config_use_netcdf4_hack() && count_sgradata == 1) {

                sh5a_sid = H5Screate(H5S_SCALAR);
                if (sh5a_sid < 0) {
                    H4toH5error_set(dt,3,"cannot create attribute space",
                             __FILE__,__LINE__);
                     free(sgr_adata);
                    return FAIL;
                }
            }
            else {

                sh5dims[0] = count_sgradata;
                sh5a_sid =  H5Screate_simple(1,sh5dims,NULL);
                    
                if (sh5a_sid < 0) {
                    H4toH5error_set(dt,3,"cannot create attribute space",
                             __FILE__,__LINE__);
                     free(sgr_adata);
                    return FAIL;
                }
            }

            sh5a_id = H5Acreate_safe(h4toh5id,sh5_dset,sgratrr_name,sh5_atype,sh5a_sid,
                H5P_DEFAULT);

            if(sh5a_id <0) {
                H4toH5error_set(dt,3,"cannot obtain attribute id",
                         __FILE__,__LINE__);
                 free(sgr_adata);
                H5Sclose(sh5a_sid);
                return FAIL;
            }

            sret = H5Awrite(sh5a_id,sh5_amemtype,(void *)sgr_adata);

            if(sret <0) {
                H4toH5error_set(dt,3,"cannot write attribute data",
                         __FILE__,__LINE__);
                 free(sgr_adata);
                H5Sclose(sh5a_sid);
                H5Aclose(sh5a_id);
                return FAIL;
            }
        }
        sret = H5Sclose(sh5a_sid);
        if(sret < 0) {
            H4toH5error_set(dt,3,"cannot write attribute data",
             __FILE__,__LINE__);
            free(sgr_adata);
            H5Aclose(sh5a_id);
            return FAIL;
        }
        if (sh5a_id >= 0) {
            sret = H5Aclose(sh5a_id);
            if(sret < 0) {
                H4toH5error_set(dt,3,"cannot write attribute data",
                 __FILE__,__LINE__);
                free(sgr_adata);
                return FAIL;
            }
        }
        free(sgr_adata);

    }

    return SUCCEED;
}
    

/*-------------------------------------------------------------------------
 * Function:    h4toh5_image
 *
 * Purpose:     translate image into hdf5 dataset
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id:   h4toh5 identifier
        ri_id:           raster image identifier
        h5filename:  hdf5 file name
        h5groupname: hdf5 group name
        h5dsetname:  hdf5 dataset name
        h5_palname:  the new hdf5 name for hdf5 dataset converted from
                     palette
        
        attr_flag: flag for attribute

 *-------------------------------------------------------------------------
 */ 

int H4toH5image(hid_t  h4toh5_id,
        int32  ri_id,
        char*  h5groupname,
                    char*  h5dsetname,
        char*  h5palgroupname,
        char*  h5palsetname,
        int      attr_flag,
        int      pal_flag)
{

    int32        istat; /* check the "return" status    of HDF4 APIs */
    int32        ngrattrs; /* number of GR interface attributes. */
    int32        ncomp; /* number of component of the image data */
    int          check_gloattr; /* temporary varible to check the global attribute */ 
    int32        start[2]; /* array to store the starting points of the image data */
    int32        edges[2]; /* array to store the ending points of the image data */
    int32        dimsizes[2]; /* array to store the size of each dimension */
    uint16   gr_ref; /* the reference number of GR interface */
    char         gr_refstr[MAXREF_LENGTH]; /* reference number of GR interface with
                    string format */
    int32        image_dtype; /* image data type */
    int          check_imagename; /* temporary variable to check the existence of
                         image name at name hash table */
    int          check_image; /* temporary variable to check the existence of
                 image at the hash table */
    int*         check_lookupptr; /* the pointer to store the return flag of 
                         status of the image hash table */
    char         image_name[H4H5_MAX_GR_NAME];/* image name */
    char         grlabel[H4H5_MAX_GR_NAME]; /* image label */
    char         image_class[H4H5_MAX_GR_NAME];/* image class name */
    char         image_index[H4H5_MAX_GR_NAME];/* image index name */

    char*        h5cimage_name; /* the absolute path of the HDF5 image */
    char*        ori_h5cimage_name; /* the absolute path of the first looked-up image*/
    void*        image_data; /* data buffer to store the image */
    HDF_CHUNK_DEF c_def_out; /* chunk struct */
    int32        c_flags; /* a flag to check the status of chunking */
    int32        interlace_mode; /* Interlace mode of the image */

    /* define varibles for hdf5. */
    hid_t        h5ty_id; /* HDF5 image data type id */
    hid_t        h5memtype; /* HDF5 image data type id in memory */ 
    hid_t        h5d_sid; /* HDF5 data space id */
    hid_t        h5_group; /* HDF5 group id */
    hid_t        h5dset; /* HDF5 dataset id */
    size_t   h4size; /* size of image data type in disk */
    size_t   h4memsize; /* size of image data type in memory */
    hsize_t  h5dims[2]; /* the size of each dimension of HDF5 dataset converted
             from 8-bit image */
    hsize_t  h5dims24[3]; /* the size of each dimension of HDF5 dataset converted
                 from 24-bit image */
    herr_t   ret; /* the temporary variable to check the "return" status of HDF5 APIs */
    hid_t        create_plist; /* creation property list of dataset*/
    int32        temp_anno; /* temporary variable to check annotation */
    int          temp; /* temporary variable */

    h4toh5id_t* temph4toh5id; /* pointer to h4toh5 id struct for 
                         passing parameters of error handlings */


    temp                        = 0;
    check_lookupptr =&temp;

    /* obtain global table*/
    temph4toh5id    = H4TOH5I_object(h4toh5_id);

    /* zeroing out memory.*/
    h4toh5_ZeroMemory(image_name,H4H5_MAX_GR_NAME);
    h4toh5_ZeroMemory(image_class,H4H5_MAX_GR_NAME);
    h4toh5_ZeroMemory(grlabel,H4H5_MAX_GR_NAME);

    /* Obtain information of the image.*/  
    if(GRgetchunkinfo(ri_id,&c_def_out,&c_flags)==FAIL){
        H4toH5error_set(temph4toh5id,2,"cannot get GR chunking information",
                 __FILE__,__LINE__);
        return FAIL;
    }

    
    istat = GRgetiminfo(ri_id, image_name, &ncomp, &image_dtype, 
                    &interlace_mode, dimsizes, &ngrattrs);
    if(istat == FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain GR general information",
                 __FILE__,__LINE__);
        return FAIL;
    }

    gr_ref = GRidtoref(ri_id);
    if(gr_ref == 0) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain GR reference number",
                 __FILE__,__LINE__);
        return FAIL;
    }
    
    /*** PART II. obtain the absolute name of hdf5 image. ***/

    /* change format of reference number. */
    if(conv_int_str(h4toh5_id,gr_ref,gr_refstr)== FAIL) {
        H4toH5error_set(temph4toh5id,5,"cannot convert reference number into string type",
                 __FILE__,__LINE__);
        return FAIL;
    }

    /* obtaining absolute path of image name.*/

    check_image = lookup(h4toh5_id,gr_ref,IMAGE_HASHSIZE,
                     temph4toh5id->gr_hashtab,&temp);

    if(h5dsetname == NULL) {
        /* Here we have to be careful:
             1) We assume the user will not use HDF4_IMAGE_REF as their own 
             image name. 
             2) We will check whether this image(by using gr_ref) is looked up
             or not, if this image is looked up, it must be assigned a name. We want
             to make sure the name we obtain is not used before. 
             3) the procedure is:
             i)     obtain the image name by using get_h5datasetname.
             ii)    check whether this name is looked up.
                        due to the possible name clashing among images(two images may
             share the same name), we will use lookup_name to check whether the
             name is touched or not.
        */

        h5cimage_name= get_h5datasetname(h4toh5_id,h5groupname,image_name,gr_ref,
                         HDF4_IMAGE,OBJECT_HASHSIZE,check_lookupptr);
        
        if(lookup_name(h4toh5_id,h5cimage_name,OBJECT_HASHSIZE,
             temph4toh5id->name_hashtab)==1) {
            H4toH5error_set(temph4toh5id,4,"this image name has been used",
                                            __FILE__,__LINE__);
            return FAIL;
        }
    }
    else { 
     
        h5cimage_name = get_h5datasetname(h4toh5_id,h5groupname,h5dsetname,gr_ref,
                            HDF4_IMAGE,OBJECT_HASHSIZE,check_lookupptr);
        /* FOR understanding this clearly, we may use lookup_name to replace
         *check_lookupptr later. */
        if(*check_lookupptr == 1) {/* the user-input image name is used.*/
            H4toH5error_set(temph4toh5id,4,"the data set name has been used",
                                            __FILE__,__LINE__);
            return FAIL;
        }
    
    }

    /* obtain h5_group id */
    h5_group        =  get_h5groupid(h5groupname,h4toh5_id,attr_flag);
    if(h5_group < 0) {
        H4toH5error_set(temph4toh5id,5,"cannot obtain  hdf5 group id",
                 __FILE__,__LINE__);
        free(h5cimage_name);
        return FAIL;
    }

    /*update the hdf5 datasets table.*/
 
    if(lookup_updatename(h4toh5_id,h5cimage_name,OBJECT_HASHSIZE,
                     temph4toh5id->name_hashtab)== -1) {
        H4toH5error_set(temph4toh5id,4,
                 "cannot allocate memory for checking h5cimage_name",
                 __FILE__,__LINE__);
        free(h5cimage_name);
        H5Gclose(h5_group);
        return FAIL;
    }

    /* check whether this image is touched, if not; put this image name into the
         image table; this will be used to create hardlink when multiple groups include one image object.*/

    if(check_image == 0) {
        /* put the absolute path of the image into "hashing table".*/
        if(set_name(h4toh5_id,gr_ref,IMAGE_HASHSIZE,
        temph4toh5id->gr_hashtab,h5cimage_name,-1)==FAIL) {
            H4toH5error_set(temph4toh5id,4,"cannot set object name properly",
                                            __FILE__,__LINE__);
            free(h5cimage_name);
            H5Gclose(h5_group);
            return FAIL;
        }
    }
 
    else {/* create a hard link ,return SUCCEED.*/
        ori_h5cimage_name = get_name(h4toh5_id,gr_ref,IMAGE_HASHSIZE,
                 temph4toh5id->gr_hashtab,&check_imagename);
        if(ori_h5cimage_name == NULL) {
            H4toH5error_set(temph4toh5id,4,
             "cannot get the name of the HDF5 dataset converted from image",
             __FILE__,__LINE__);
            free(h5cimage_name);
            H5Gclose(h5_group);
            return FAIL;
        }
        if(H5Glink(h5_group,H5G_LINK_HARD,ori_h5cimage_name,h5cimage_name) <0) {
            H4toH5error_set(temph4toh5id,3,"cannot set up hard link to original dataset name",
             __FILE__,__LINE__);
            free(h5cimage_name);
            free(ori_h5cimage_name);
            H5Gclose(h5_group);
            return FAIL;
        }
        free(h5cimage_name);
        free(ori_h5cimage_name);
        ret = H5Gclose(h5_group);
        if(ret < 0) {
            H4toH5error_set(temph4toh5id,3,
             "cannot close HDF5 group",
             __FILE__,__LINE__);
            return FAIL;
        }
        return SUCCEED;
    }

    /** OBTAIN IMAGE DATA **/
        /* data type transferring from hdf4 to hdf5. */
    if(h4type_to_h5type(h4toh5_id,image_dtype,&h5memtype,&h4memsize,
                    &h4size,&h5ty_id)== FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot convert HDF4 data type into HDF5 data type",
                 __FILE__,__LINE__);
        free(h5cimage_name);
        H5Gclose(h5_group);
        return FAIL;
    }
 
    /* check whether the datatype is string. */
    
    if (h5ty_id == H5T_STRING) {
        /* rechange string datatype into numerical datatype.*/
        if(h5string_to_int(h4toh5_id,image_dtype,&h5memtype,h4memsize,
                     &h5ty_id)== FAIL) {
            H4toH5error_set(temph4toh5id,3,"cannot obtain attribute id",
                                            __FILE__,__LINE__);
            free(h5cimage_name);
            H5Gclose(h5_group);
            return FAIL;
        }
    }           

    start[0]     = 0;
    start[1]     = 0;
    edges[0]     = dimsizes[0];
    edges[1]     = dimsizes[1];
    
    image_data = malloc(h4memsize*dimsizes[0]*dimsizes[1]*ncomp);
    
    if(image_data == NULL) {
        H4toH5error_set(temph4toh5id,1,"cannot allocate memory for image data",
                 __FILE__,__LINE__);
        free(h5cimage_name);
        H5Gclose(h5_group);
        return FAIL;
    }

    istat = GRreadimage(ri_id, start, NULL, edges, (VOIDP)image_data);

    if (istat == FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot read GR image data",
                 __FILE__,__LINE__);
        free(image_data);
        free(h5cimage_name);
        H5Gclose(h5_group);
        return FAIL;
    }
    

    /*end of obtaining data. */

    /****  check number of component of the image object,
     and transfer HDF4 object into HDF5 object. ****/

    if (ncomp <= 0) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain image component",
                 __FILE__,__LINE__);
        free(image_data);
        free(h5cimage_name);
        H5Gclose(h5_group);
        return FAIL;
    }

    /* create property list. */

    create_plist = get_image_chunking_plistid(h4toh5_id,ri_id);
    if(create_plist == -1) {
        H4toH5error_set(temph4toh5id,3,
                 "unable to create property list",
                 __FILE__,__LINE__);
        free(h5cimage_name);
        H5Gclose(h5_group);
        free(image_data);
        return FAIL;
    }
    
    if (ncomp == 1) {

     
        h5dims[0] = edges[1]-start[1];
        h5dims[1] = edges[0]-start[0];
        h5d_sid = H5Screate_simple(2,h5dims,NULL);
        if(h5d_sid <0) {
            H4toH5error_set(temph4toh5id,3,
             "unable to create space for dataset",
             __FILE__,__LINE__);
            free(image_data);
            free(h5cimage_name);
            H5Pclose(create_plist);
            H5Gclose(h5_group);
            return FAIL;
        }
                    
        h5dset  = H5DCREATE(h5_group,h5cimage_name,h5ty_id,h5d_sid,create_plist);
        
        if(h5dset < 0) {
            H4toH5error_set(temph4toh5id,3,
             "unable to create HDF5 dataset converted from images",
             __FILE__,__LINE__);
            free(image_data);
            free(h5cimage_name);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid);
            H5Gclose(h5_group);
            return FAIL;
        }

        if (H5Dwrite(h5dset,h5memtype,h5d_sid,h5d_sid,H5P_DEFAULT,
         image_data)<0) {
            H4toH5error_set(temph4toh5id,3,
             "unable to write data for HDF5 dataset converted from images",
             __FILE__,__LINE__);
            free(image_data);
            free(h5cimage_name);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid);
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        }
    
    }

    else { 

     
        if(interlace_mode == MFGR_INTERLACE_PIXEL){
            h5dims24[0] = edges[1]-start[1];
            h5dims24[1] = edges[0]-start[0];
            h5dims24[2] = 3;
        }
        /* currently scan-line is not supported.*/
        else if (interlace_mode == MFGR_INTERLACE_LINE){
            /*printf("currently line interleaving is not supported.\n");
            printf("the image %s will not be converted.\n",image_name);*/
            free(image_data);
            free(h5cimage_name);
            H5Pclose(create_plist);
            H5Gclose(h5_group);
            return SUCCEED;
         /* h5dims24[0] = 3;
            h5dims24[1] = edges[1]-start[1];
            h5dims24[2] = edges[0]-start[0]; */
        }
        else if (interlace_mode == MFGR_INTERLACE_COMPONENT){
            h5dims24[0] = 3;
            h5dims24[1] = edges[1]-start[1];
            h5dims24[2] = edges[0]-start[0];
        }

        else {/* treat as pixel */
            h5dims24[0] = edges[1]-start[1];
            h5dims24[1] = edges[0]-start[0];
            h5dims24[2] = 3;
        }

        h5d_sid         = H5Screate_simple(3,h5dims24,NULL);
        if(h5d_sid < 0) {
            H4toH5error_set(temph4toh5id,3,
             "unable to create HDF5 data space",
             __FILE__,__LINE__);
            free(image_data);
            free(h5cimage_name);
            H5Pclose(create_plist);
            H5Gclose(h5_group);
            return FAIL;
        }

        h5dset          = H5DCREATE(h5_group,h5cimage_name,h5ty_id,h5d_sid,
                    create_plist);
        if(h5dset < 0) {
            H4toH5error_set(temph4toh5id,3,
             "unable to create HDF5 dataset",
             __FILE__,__LINE__);
            free(image_data);
            free(h5cimage_name);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid);
            H5Gclose(h5_group);
            return FAIL;
        }

        if (H5Dwrite(h5dset,h5memtype,h5d_sid,h5d_sid,H5P_DEFAULT,
         (void *)image_data)<0) {
            H4toH5error_set(temph4toh5id,3,
             "unable to write HDF5 data",
             __FILE__,__LINE__);
            free(image_data);
            free(h5cimage_name);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid);
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        } 

    }

    free(image_data);
    /* converting the necessary image attributes according to
         HDF5 image specification. 
         */
    
    if(h4_transpredattrs(h4toh5_id,h5dset,HDF4_IMAGE_VERSION_ATTR,
                     HDF5IMAGE_SPE_VERSION)==FAIL){
            H4toH5error_set(temph4toh5id,5,
             "unable to generate OBJECT NAME attribute",
             __FILE__,__LINE__);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            free(h5cimage_name);
            return FAIL;
    }

    if(attr_flag != H425_NO_PREDEF_ATTRS && attr_flag!= H425_SV) {
        if(h4_transpredattrs(h4toh5_id,h5dset,HDF4_OBJECT_NAME,image_name)==FAIL){
            H4toH5error_set(temph4toh5id,5,
             "unable to generate OBJECT NAME attribute",
             __FILE__,__LINE__);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            free(h5cimage_name);
            return FAIL;
        }
    }

    strcpy(image_class,IM_CLASS);
    
    if(h4_transpredattrs(h4toh5_id,h5dset,HDF4_IMAGE_CLASS,image_class)==FAIL){
            H4toH5error_set(temph4toh5id,5,
            "unable to generate IMAGE CLASS attributes",
            __FILE__,__LINE__);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            free(h5cimage_name);
            return FAIL;
    }

    if(ncomp == 3 && h4size==1) {
        strcpy(image_index,HDF4_IMAGE_TRUECOLOR);
        if(h4_transpredattrs(h4toh5_id,h5dset,HDF4_IMAGE_SUBCLASS,image_index)== FAIL) {
           H4toH5error_set(temph4toh5id,5,
            "unable to generate IMAGE CLASS attributes",
            __FILE__,__LINE__);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            free(h5cimage_name);
            return FAIL;
        }
    }
    if(ncomp == 1 && h4size ==1) {
        strcpy(image_index,HDF4_IMAGE_INDEXED);
        if(h4_transpredattrs(h4toh5_id,h5dset,HDF4_IMAGE_SUBCLASS,image_index)== FAIL) {
           H4toH5error_set(temph4toh5id,5,
            "unable to generate IMAGE CLASS attributes",
            __FILE__,__LINE__);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            free(h5cimage_name);
            return FAIL;
       }
    }
    if(ncomp >1) {
        if(interlace_mode == MFGR_INTERLACE_PIXEL){
            if(h4_transpredattrs(h4toh5_id,h5dset,INTERLACE_MODE,PIXEL_INTERLACE)==FAIL){
               H4toH5error_set(temph4toh5id,5,
               "unable to generate IMAGE interlace mode attribute",
               __FILE__,__LINE__);
               H5Pclose(create_plist);
               H5Sclose(h5d_sid); 
               H5Dclose(h5dset);
               H5Gclose(h5_group);
               free(h5cimage_name);
               return FAIL;
            }
        }
        /* currently scan-line is not supported.
        else if (interlace_mode == MFGR_INTERLACE_LINE){
         if(h4_transpredattrs(h4toh5_id,h5dset,INTERLACE_MODE,LINE_INTERLACE)==FAIL){
            H4toH5error_set(temph4toh5id,5,
         "unable to generate IMAGE interlace mode attribute",
         __FILE__,__LINE__);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            free(h5cimage_name);
            return FAIL;
            }
            }*/
        else if (interlace_mode == MFGR_INTERLACE_COMPONENT){
            if(h4_transpredattrs(h4toh5_id,h5dset,INTERLACE_MODE,PLANE_INTERLACE)==FAIL){
               H4toH5error_set(temph4toh5id,5,
               "unable to generate IMAGE interlace mode attribute",
               __FILE__,__LINE__);
               H5Pclose(create_plist);
               H5Sclose(h5d_sid); 
               H5Dclose(h5dset);
               H5Gclose(h5_group);
               free(h5cimage_name);
               return FAIL;
            }
        }
     
        else {/* treat as pixel interlace mode. */
            if(h4_transpredattrs(h4toh5_id,h5dset,INTERLACE_MODE,PIXEL_INTERLACE)==FAIL){
               H4toH5error_set(temph4toh5id,5,
               "unable to generate IMAGE interlace mode attribute",
               __FILE__,__LINE__);
               H5Pclose(create_plist);
               H5Sclose(h5d_sid); 
               H5Dclose(h5dset);
               H5Gclose(h5_group);
               free(h5cimage_name);
               return FAIL;
            }
        } 
            
    }
    /* convert image annotation into attribute of image dataset.
         Since there are no routines to find the exact tag of the image object,
         we will check three possible object tags of image objects, that is:
         DFTAG_RIG,DFTAG_RI,DFTAG_RI8. If the object tag of image object is 
         falling out of this scope, we will not convert annotations into
         hdf5 attributes; it is user's responsibility to make sure object tags
         for image objects are only one of the above three tags.*/

    if(is_valid_attr_flag(attr_flag)==0) {
        H4toH5error_set(temph4toh5id,5,
                 "attribute flag is set wrong",
                 __FILE__,__LINE__);
        free(h5cimage_name);
        H5Pclose(create_plist);
        H5Sclose(h5d_sid); 
        H5Dclose(h5dset);
        H5Gclose(h5_group);
        return FAIL;    
    }

    if(pal_flag <0 || pal_flag > 1) {
        H4toH5error_set(temph4toh5id,5,
                 "palette flag is set wrong",
                 __FILE__,__LINE__);
        free(h5cimage_name);
        H5Pclose(create_plist);
        H5Sclose(h5d_sid); 
        H5Dclose(h5dset);
        H5Gclose(h5_group);
        return FAIL;    
    }

    if(is_valid_attr_flag(attr_flag) && attr_flag != H425_NOATTRS) {
        temp_anno = H4toH5anno_obj_all_labels_new(h4toh5_id,h5groupname,h5cimage_name,
                             gr_ref,DFTAG_RIG,attr_flag);        
        if(temp_anno== FAIL){
            H4toH5error_set(temph4toh5id,5,
            "GR annotation object label conversion is wrong",
            __FILE__,__LINE__);
            free(h5cimage_name);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        }
    
        temp_anno = H4toH5anno_obj_all_labels_new(h4toh5_id,h5groupname,h5cimage_name,
                             gr_ref,DFTAG_RI8,attr_flag);
        
        if(temp_anno== FAIL){
            H4toH5error_set(temph4toh5id,5,
            "RI8 annotation object label conversion is wrong",
            __FILE__,__LINE__);
            free(h5cimage_name);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        }
 
        temp_anno = H4toH5anno_obj_all_labels_new(h4toh5_id,h5groupname,h5cimage_name,
                             gr_ref,DFTAG_RI,attr_flag);
        
        if(temp_anno== FAIL){
            H4toH5error_set(temph4toh5id,5,
            "RI annotation object label conversion is wrong",
            __FILE__,__LINE__);
            free(h5cimage_name);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        }

        temp_anno = H4toH5anno_obj_all_descs_new(h4toh5_id,h5groupname,h5cimage_name,
                             gr_ref,DFTAG_RIG,attr_flag);
        
        if(temp_anno== FAIL){
            H4toH5error_set(temph4toh5id,5,
            "GR annotation object description conversion is wrong",
            __FILE__,__LINE__);
            free(h5cimage_name);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        }
    
        temp_anno = H4toH5anno_obj_all_descs_new(h4toh5_id,h5groupname,h5cimage_name,
                             gr_ref,DFTAG_RI8,attr_flag);
        
        if(temp_anno== FAIL){
            H4toH5error_set(temph4toh5id,5,
            "RI8 annotation object description conversion is wrong",
            __FILE__,__LINE__);
            free(h5cimage_name);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        }
 
        temp_anno = H4toH5anno_obj_all_descs_new(h4toh5_id,h5groupname,h5cimage_name,
                             gr_ref,DFTAG_RI,attr_flag);
        
        if(temp_anno== FAIL){
            H4toH5error_set(temph4toh5id,5,
            "RI annotation object description conversion is wrong",
            __FILE__,__LINE__);
            free(h5cimage_name);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        }
    
        /************************************/
        /* translate GR attributes into HDF5 dataset attribute.*/

        check_gloattr = 0;
        if(gr_tranattrs(h4toh5_id,ri_id,h5dset,ngrattrs,check_gloattr,attr_flag)==FAIL){ 
            H4toH5error_set(temph4toh5id,5,
            "unable to convert GR attribute",
            __FILE__,__LINE__);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        }

        /*  deal with h5dset predefined and user-defined attributes. 
       Obtain the name and data type and the total number of attributes.  
       Data attribute at hdf4 is only one-dimensional array. */
    
        if (ncomp == 1 && h4size == 1)
            strcpy(grlabel,RAST8LABEL);
        else if(ncomp == 3 && h4size == 1)
            strcpy(grlabel,RAST24LABEL);
        else
            strcpy(grlabel,GRLABEL);

        /* transfer hdf4 predefined attributes into hdf5 dataset.*/
        if(attr_flag == H425_OSPEC_ALLATTRS || attr_flag == H425_ALLATTRS){
            if(h4_transpredattrs(h4toh5_id,h5dset,HDF4_OBJECT_TYPE,grlabel)==FAIL){
                H4toH5error_set(temph4toh5id,5,
                "unable to generate OBJECT TYPE attribute",
                __FILE__,__LINE__);
                H5Pclose(create_plist);
                H5Sclose(h5d_sid); 
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
                return FAIL;
            }

            if(h4_transnumattr(h4toh5_id,h5dset,HDF4_REF_NUM,gr_ref)==FAIL) {
                H4toH5error_set(temph4toh5id,5,
                "unable to generate image reference number attribute",
                __FILE__,__LINE__);
                H5Pclose(create_plist);
                H5Sclose(h5d_sid); 
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
                return FAIL;
            }
        }
    }

    /* deal with palette. */
    if(pal_flag == H425_PAL){
        if(H4toH5pal(h4toh5_id,ri_id,h5groupname,h5dsetname,h5palgroupname,
            h5palsetname,attr_flag,H425_PAL)== FAIL) {
            H4toH5error_set(temph4toh5id,5,
                "unable to convert palette to HDF5 dataset",
                __FILE__,__LINE__);
            H5Pclose(create_plist);
            H5Sclose(h5d_sid); 
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            free(h5cimage_name);
            return FAIL;
        }
    }
    ret     = H5Pclose(create_plist);
    if(ret < 0) {
        H4toH5error_set(temph4toh5id,3,
            "unable to close property list interface",
            __FILE__,__LINE__);
        H5Sclose(h5d_sid); 
        H5Dclose(h5dset);
        H5Gclose(h5_group);
        free(h5cimage_name);
        return FAIL;
    }
    ret     = H5Sclose(h5d_sid); 
    if(ret < 0) {
        H4toH5error_set(temph4toh5id,3,
         "unable to close data space interface",
         __FILE__,__LINE__);
        H5Dclose(h5dset);
        H5Gclose(h5_group);
        free(h5cimage_name);
        return FAIL;
    }
    ret     = H5Dclose(h5dset);
    if(ret < 0) {
        H4toH5error_set(temph4toh5id,3,
         "unable to close data set interface",
         __FILE__,__LINE__);
        H5Gclose(h5_group);
        free(h5cimage_name);
        return FAIL;
    }
    ret     = H5Gclose(h5_group);
    if(ret < 0) {
        H4toH5error_set(temph4toh5id,3,
         "unable to close group interface",
         __FILE__,__LINE__);
        free(h5cimage_name);
        return FAIL;
    }

    free(h5cimage_name);
    return SUCCEED;
}

/*-------------------------------------------------------------------------
 * Function:    H4toH5image_attr_name
 *
 * Purpose:     translate attributes of Image object into HDF5 dataset
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
 
        h4toh5_id:  h4toh5 identifier
        ri_id:       SDS identifier
        h5groupfullpath: hdf5 group name(must be provided)
        h5dsetname: hdf5 dataset name(can be set NULL)
        h4attrname: hdf4 attribute name
 
 Out:                   
 *-------------------------------------------------------------------------
 */ 

int H4toH5image_attr_name(hid_t h4toh5id,
             int32 ri_id, 
             char* h5groupfullpath,
             char* h5dsetname,
             char* h4attrname)
{

    h4toh5id_t *temph4toh5id; /* pointer to h4toh5id struct */
    int h4index; /* the index of HDF4 attribute */

    temph4toh5id = H4TOH5I_object(h4toh5id);
    if ((h4index=GRfindattr(ri_id,h4attrname))==FAIL) {
        H4toH5error_set(temph4toh5id,2,
                 "unable to find index from the attribute name",
                 __FILE__,__LINE__);
        return FAIL;
    }
    if(H4toH5image_attr_index(h4toh5id,ri_id,h5groupfullpath,h5dsetname,h4index)==FAIL){
        H4toH5error_set(temph4toh5id,5,"unable to convert image attribute",
                 __FILE__,__LINE__);
        return FAIL;
    }
    return SUCCEED;
}

/*-------------------------------------------------------------------------
 * Function:    H4toH5image_attr_index
 *
 * Purpose:     translate attributes of Image object into HDF5 dataset
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
 
        h4toh5_id:  h4toh5 identifier
        ri_id:       SDS identifier
        h5groupfullpath: hdf5 group name(must be provided)
        h5dsetname: hdf5 dataset name(can be set NULL)
        h4index:            attribute index
 
 Out:                   
 *-------------------------------------------------------------------------
 */ 

int H4toH5image_attr_index(hid_t h4toh5id,
             int32 ri_id, 
             char* h5groupfullpath,
             char* h5dsetname,
             int     h4index)
{
        
    char            sgratrr_name[2*H4H5_MAX_NC_NAME]; /* GR attribute name */
    char*           grrepattr_name; /* temporary GR attribute name */
    int32           count_sgradata; /* number of the element of GR attribute */
    int32           sgr_atype; /* GR attribute data type */
    size_t      sh4_amemsize; /* the size of image attribute data type in memory */
    size_t      sh4_asize; /* the size of image attribute data type in disk */
    int32           ncomp; /* number of componet */
    uint16      gr_ref; /* reference number of image */
    char            refstr[MAXREF_LENGTH]; /* reference number of GR interface with
                    string format */
    char            image_name[H4H5_MAX_GR_NAME];/* image name */
    char*           h5cimage_name; /* the absolute path of the HDF5 image */
    char*           h5crepimage_name; /* temporary string to store the HDF5 image name*/
    int32           image_dtype; /* image data type */
    int32           interlace_mode; /* Interlace mode of the image */
    int32           dimsizes[2]; /* array to store the size of each dimension */
    int32           ngrattrs; /* number of image attributes*/

    hid_t           sh5a_sid;/* HDF5 attribute data space id */
    hid_t           sh5a_id; /* HDF5 attribute id */
    hid_t           sh5_atype; /* HDF5 attribute data type */
    hid_t           sh5_amemtype; /* HDF5 attribute data type id in memory */ 
    hid_t           sh5str_type; /* image attribute data type(in disk) with the HDF5 
                    string format */
    hid_t           sh5str_memtype; /* image attribute data type(in memory) with the 
                         HDF5 string format */
    hid_t           h5dset; /* HDF5 dataset id */
    hid_t           h5_group; /* HDF5 group id */
    hsize_t     sh5dims[H4_MAX_VAR_DIMS]; /* the size of each dimension of the image */
    void*           sgr_adata; /* data buffer to store image attribute data */
    herr_t      sret; /* the temporary variable to check the return status of
                 HDF5 interfaces. */
    int32           istat; /* the temporary variable to check the return status of
                    HDF4 interfaces. */

    int*            check_lookupptr; /*  the pointer to store the return flag of 
                         status of the image hash table */
    int             temp;
    char*           cor_image_name;
    char*           cor_h5dsetname;
    h4toh5id_t* dt;/* pointer to h4toh5 id struct for 
                passing parameters of error handlings */

    temp = 0;
    check_lookupptr = &temp;
    dt = H4TOH5I_object(h4toh5id);

    /* The following block obtains group name and dataset name. */

    /* obtain h5_group id */
    h5_group        =  get_h5groupid(h5groupfullpath,h4toh5id,H425_OSPEC_ALLATTRS);
    if(h5_group < 0) {
        H4toH5error_set(dt,5,
                 "cannot obtain HDF5 group ID",
                 __FILE__,__LINE__);
        return FAIL;
    }

    /* part II. obtain the hdf5  name. */
    /*obtaining reference number and name of h5 dataset 
        corresponding to sds. */

    /*obtain name,rank,dimsizes,datatype and num of attributes of sds */

    istat = GRgetiminfo(ri_id, image_name, &ncomp, &image_dtype, 
                    &interlace_mode, dimsizes, &ngrattrs);
    if(istat == FAIL) {
        H4toH5error_set(dt,2,"cannot obtain GR general information",
                 __FILE__,__LINE__);
        H5Gclose(h5_group);
        return FAIL;
    }

    gr_ref = GRidtoref(ri_id);
    if(gr_ref == 0) {
        H4toH5error_set(dt,2,"cannot obtain GR reference number",
                 __FILE__,__LINE__);
         H5Gclose(h5_group);
        return FAIL;
    }

    if(h5dsetname == NULL) {

        /* change format of reference number. */
        if(conv_int_str(h4toh5id,gr_ref,refstr)== FAIL) {
            H4toH5error_set(dt,5,"cannot convert reference number into string type",
                 __FILE__,__LINE__);
            return FAIL;
        }
            /* for logic, see comments of dimscale at h4toh5sds.c */
        h5crepimage_name = make_objname_no(h4toh5id,refstr,h5groupfullpath,
                         HDF4_IMAGE);
        if(lookup_name(h4toh5id,h5crepimage_name,IMAGE_HASHSIZE,
                     dt->name_hashtab)==1){
            h5cimage_name = malloc(strlen(h5crepimage_name)+1);
            if(h5cimage_name == NULL) {
                H4toH5error_set(dt,1,"cannot allocate memory for image name",
                     __FILE__,__LINE__);
                return FAIL;
            }
            strncpy(h5cimage_name,h5crepimage_name,strlen(h5crepimage_name));
        }

        else {
            cor_image_name = correct_name(h4toh5id,image_name);
            if(cor_image_name == NULL) {
                H4toH5error_set(dt,4,
                 "cannot obtain corrected image name",__FILE__,__LINE__);
                return FAIL;
            }
            h5cimage_name = make_objname_yes(h4toh5id,cor_image_name,h5groupfullpath);
            free(cor_image_name);
        }
        free(h5crepimage_name);
    }
    else {
        cor_h5dsetname = correct_name(h4toh5id,h5dsetname);
        if(cor_h5dsetname == NULL) {
            H4toH5error_set(dt,4,
             "cannot obtain corrected HDF5 dataset name",__FILE__,__LINE__);
                return FAIL;
        }
        h5cimage_name = make_objname_yes(h4toh5id,cor_h5dsetname,h5groupfullpath);
        free(cor_h5dsetname);
    }

    h5dset = H5DOPEN(h5_group,h5cimage_name);
    if(h5dset < 0){
        H4toH5error_set(dt,3,"cannot open HDF5 dataset",
         __FILE__,__LINE__);
        free(h5cimage_name);
        H5Gclose(h5_group);
        return FAIL;
    }

    if (GRattrinfo(ri_id,h4index,sgratrr_name,&sgr_atype,&count_sgradata)==FAIL){  
        H4toH5error_set(dt,2,"cannot obtain image attribute information",
                               __FILE__,__LINE__);
        free(h5cimage_name);
        H5Dclose(h5dset);
        H5Gclose(h5_group);
        return FAIL;
    }
         
    /*convert datatype for attribute. */

    if(h4type_to_h5type(h4toh5id,sgr_atype,&sh5_amemtype,&sh4_amemsize,
        &sh4_asize,&sh5_atype)==FAIL){
        H4toH5error_set(dt,5,"cannot convert hdf4 datatype into hdf5 datatype",
                               __FILE__,__LINE__);
        free(h5cimage_name);
        H5Dclose(h5dset);
        H5Gclose(h5_group);
        return FAIL;
    }

    sgr_adata = malloc(sh4_amemsize*count_sgradata);
    if(sgr_adata == NULL) {
        H4toH5error_set(dt,1,"cannot allocate memory for GR attribute data",
                               __FILE__,__LINE__);
        free(h5cimage_name);
        H5Dclose(h5dset);
        H5Gclose(h5_group);
        return FAIL;
    }

    if(GRgetattr(ri_id,h4index,(VOIDP)sgr_adata)==FAIL){
        H4toH5error_set(dt,5,"cannot get GR attribute data",
                               __FILE__,__LINE__);
        free(sgr_adata);
         free(h5cimage_name);
        H5Dclose(h5dset);
        H5Gclose(h5_group);
        return FAIL;
    }
    
    /* if attribute doesn't have name, a default name is set. */
    if(sgratrr_name[0] == '\0') {
        grrepattr_name = trans_obj_name(h4toh5id,DFTAG_RIG,h4index);
        strcpy(sgratrr_name,grrepattr_name);
        free(grrepattr_name);
    }

    
    /* now do attribute-transferring.
             1. deal with string data type
             2. set attribute space.
             3. get attribute name, set property list. */
                     
    if (sh5_atype == H5T_STRING) {

        sh5a_sid = H5Screate(H5S_SCALAR);
        if (sh5a_sid < 0) {
            H4toH5error_set(dt,3,"cannot create attribute space for image",
             __FILE__,__LINE__);
            free(sgr_adata);
            free(h5cimage_name);
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        }

        if ((sh5str_type = mkstr(h4toh5id,count_sgradata*sh4_asize,
                         H5T_STR_NULLTERM))<0){
            H4toH5error_set(dt,3,"cannot make HDF5 string for image attribute ",
             __FILE__,__LINE__);
             free(sgr_adata);
            H5Sclose(sh5a_sid);
             free(h5cimage_name);
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
            }

        if ((sh5str_memtype = mkstr(h4toh5id,count_sgradata*sh4_amemsize,
                    H5T_STR_NULLTERM))<0){
            H4toH5error_set(dt,3,"cannot create attribute space for IMAGE",
             __FILE__,__LINE__);
            free(sgr_adata);
            H5Sclose(sh5a_sid);
            free(h5cimage_name);
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        }

        sh5a_id = H5Acreate_safe(h4toh5id,h5dset,sgratrr_name,sh5str_type,sh5a_sid,
                H5P_DEFAULT);
        if (sh5a_id <0) {
            if (transattrs_split(h4toh5id, h5dset, sgratrr_name, sh5a_sid, sgr_adata, count_sgradata) < 0) {
                H4toH5error_set(dt,3,"cannot obtain attribute id",
                                 __FILE__,__LINE__);
                H5Sclose(sh5a_sid);
                free(sgr_adata);
                free(h5cimage_name);
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                return FAIL;
            }
        }
        else if (H5Awrite(sh5a_id,sh5str_memtype,(void *)sgr_adata) < 0) {
            H4toH5error_set(dt,3,"cannot write attribute data",
             __FILE__,__LINE__);
            H5Sclose(sh5a_sid);
            H5Aclose(sh5a_id);
            free(h5cimage_name);
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            free(sgr_adata);
            return FAIL;
        }

    }
     
    else {
            
        if (count_sgradata == 1) {

            sh5a_sid = H5Screate(H5S_SCALAR);
            if (sh5a_sid < 0) {
                H4toH5error_set(dt,3,"cannot create attribute space",
                         __FILE__,__LINE__);
                free(sgr_adata);
                free(h5cimage_name);
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                return FAIL;
            }
        }
        else {

            sh5dims[0] = count_sgradata;
            sh5a_sid =  H5Screate_simple(1,sh5dims,NULL);
                    
            if (sh5a_sid < 0) {
                H4toH5error_set(dt,3,"cannot create attribute space",
                         __FILE__,__LINE__);
                free(sgr_adata);
                free(h5cimage_name);
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                return FAIL;
            }
        }

        sh5a_id = H5Acreate_safe(h4toh5id,h5dset,sgratrr_name,sh5_atype,sh5a_sid,
                H5P_DEFAULT);

        if(sh5a_id <0) {
            H4toH5error_set(dt,3,"cannot obtain attribute id",
                      __FILE__,__LINE__);
            free(sgr_adata);
            H5Sclose(sh5a_sid);
            free(h5cimage_name);
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        }

        sret = H5Awrite(sh5a_id,sh5_amemtype,(void *)sgr_adata);

        if(sret <0) {
            H4toH5error_set(dt,3,"cannot write attribute data",
                     __FILE__,__LINE__);
            free(sgr_adata);
            H5Sclose(sh5a_sid);
            H5Aclose(sh5a_id);
            free(h5cimage_name);
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        }
    }

    /* close all interfaces */
    sret = H5Sclose(sh5a_sid);
    if(sret < 0) {
        H4toH5error_set(dt,3,"cannot close attribute data space interface",
             __FILE__,__LINE__);
        H5Aclose(sh5a_id);
        free(h5cimage_name);
        free(sgr_adata);
        H5Dclose(h5dset);
        H5Gclose(h5_group);
        return FAIL;
    }
    if (sh5a_id >= 0) {
        sret = H5Aclose(sh5a_id);
        if(sret < 0) {
            H4toH5error_set(dt,3,"cannot close attribute interface",
                 __FILE__,__LINE__);
            free(h5cimage_name);
            free(sgr_adata);
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            return FAIL;
        }
    }
            
    sret = H5Dclose(h5dset);
    if(sret < 0) {
        H4toH5error_set(dt,3,"cannot close dataset interface",
             __FILE__,__LINE__);
        free(h5cimage_name);
        free(sgr_adata);
        H5Dclose(h5dset);
        H5Gclose(h5_group);
        return FAIL;
    }
    sret = H5Gclose(h5_group);
    if(sret < 0) {
        H4toH5error_set(dt,3,"cannot close group interface",
             __FILE__,__LINE__);
        free(h5cimage_name);
        free(sgr_adata);
        return FAIL;
    }
    
    free(sgr_adata);
    free(h5cimage_name);
    return SUCCEED;
}
/*-------------------------------------------------------------------------
 * Function:    H4toH5all_lone_image
 *
 * Purpose:         convert all independent Image objects to HDF5 datasets
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
                                h4toh5id: h4toh5 identifier
                                h5groupname: absolute path of HDF5 group
        h5_dimgroupfullpath: absolute path of HDF5 palette group
        pal_flag: palette flag
        attr_flag: attribute flag
 *-------------------------------------------------------------------------
 */ 

int H4toH5all_lone_image(hid_t h4toh5id,
                     char* h5groupname,
                     char* h5_palgroupfullpath,
                     int pal_flag,
                     int attr_flag)
{

    int32            file_id; /* HDF4 file id */
    int32            gr_id; /* GR interface id */
    int32            ri_id; /* raster image id */
    int32            ri_ref; /* raster image reference */
    int32            num_image; /* number of images */
    int32            num_glgrattrs; /* number of GR interface attributes */
    int              check_image; /* A flag to check whether the image is touched. */
    int              i,temp; /* temporary variables */
    int32            istat; /* the temporary variable to check the return status of
                    HDF4 interfaces. */              
    h4toh5id_t* temph4toh5id; /* pointer to h4toh5 id struct for 
                         passing parameters of error handlings */

    temp = 0;

    /* obtain global table*/
    temph4toh5id = H4TOH5I_object(h4toh5id);
    file_id          = temph4toh5id->file_id;
    gr_id                = temph4toh5id->gr_id;
    if(GRfileinfo(gr_id,&num_image,&num_glgrattrs) == FAIL) {
        H4toH5error_set(temph4toh5id,2,
                 "error in obtaining IMAGE information from the file",
                 __FILE__,__LINE__);
        return FAIL;
    }

    /* find all IMAGE objects under certain vgroups and update the cache table.*/
    if (checkvringobject(h4toh5id,file_id)==FAIL){
        H4toH5error_set(temph4toh5id,2,
                 "cannot check HDF4 SDS and image objects properly",
                 __FILE__,__LINE__);
        return FAIL;
    }
    /*convert all independent IMAGE objects to the group specified by 
        h5groupname. */
    for (i=0;i<num_image;i++){
        ri_id  = GRselect(gr_id,i);
        if (ri_id == FAIL) {
             H4toH5error_set(temph4toh5id,2,
             "error in obtaining raster image id",
             __FILE__,__LINE__);
              return FAIL;
        }
        ri_ref = GRidtoref(ri_id);
        check_image = lookup(h4toh5id,ri_ref,IMAGE_HASHSIZE,
                     temph4toh5id->gr_hashtab,&temp);
        if(check_image == 1) {
             GRendaccess(ri_id);
             continue;
        }
        
        if(H4toH5image(h4toh5id,ri_id,h5groupname,NULL,h5_palgroupfullpath,NULL,
             attr_flag,pal_flag)==FAIL){
            H4toH5error_set(temph4toh5id,5,"error in converting IMAGE objects.",
                                            __FILE__,__LINE__);
            GRendaccess(ri_id);
            return FAIL;
        }
        istat = GRendaccess(ri_id);
        if(istat == FAIL) {
            H4toH5error_set(temph4toh5id,3,"error in converting IMAGE objects.",
                                            __FILE__,__LINE__);
            return FAIL;
        }
    }

    return SUCCEED;
}



/*-------------------------------------------------------------------------
 * Function:    get_image_chunking_plistid
 *
 * Purpose:     get HDF5 dataset creation property list id converted from
                                SDS
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
                h4toh5id: h4toh5 identifier
                sds_id: SDS identifier
 *-------------------------------------------------------------------------
 */  
hid_t get_image_chunking_plistid(hid_t h4toh5id,int32 image_id)
{

    HDF_CHUNK_DEF c_def_out; /* HDF4 chunking defination struct */
    hsize_t  chunk_dims[2]; /* chunking dimensions */
    hsize_t  chunk_dims24[3];
    int32       c_flags;         /* flag to set for chunking */
    hid_t create_plist;/* property list id to handle chunking info */
    int32       image_dtype; /* IMAGE data type id */
    int32       image_ref;   /* IMAGE reference number */
    int32       num_imageattrs; /* number of IMAGE attributes */
    char        imagename[H4H5_MAX_GR_NAME];/* IMAGE name */
    int32       image_dimsizes[2];
    h4toh5id_t *temph4toh5id; /* a pointer to h4toh5 id*/

    int32 interlace_mode;
    int32 ncomp;

     /* for checking compression */
    int32                       file_id;
    comp_coder_t        comp_coder_type;
    comp_info                    c_info;
    /*
    int16                       special_code;
    int32                       access_id;
    uint16                  ri_ref;
    */
    int                         gzip_level;
    int                         szip_pixels_per_block;                  
    int                         options_mask;

    c_flags = -1;
    temph4toh5id = H4TOH5I_object(h4toh5id);
    file_id = temph4toh5id->file_id;

    /*obtaining reference number and name of h5 dataset 
        corresponding to image. */
    image_ref = GRidtoref(image_id);
    if(image_ref == FAIL) {
        H4toH5error_set(temph4toh5id,2,
                 "cannot obtain IMAGE reference number",
                 __FILE__,__LINE__);
        return FAIL;
    }

    if(GRgetchunkinfo(image_id,&c_def_out, &c_flags)== FAIL) {
            H4toH5error_set(temph4toh5id,2,
        "unable to obtain IMAGE chunking information",
         __FILE__,__LINE__);
        return FAIL;
    }

    if(GRgetcompinfo(image_id,&comp_coder_type,&c_info)==FAIL) {
        H4toH5error_set(temph4toh5id,3,
                         "unable to obtain gr compression information.",
                        __FILE__,__LINE__);
        return FAIL;

    }

    /*obtain name,rank,dimsizes,datatype and num of attributes of image */
    if (GRgetiminfo(image_id,imagename,&ncomp,&image_dtype,&interlace_mode,
                image_dimsizes,&num_imageattrs)==FAIL) {
            H4toH5error_set(temph4toh5id,2,
                 "unable to get IMAGE information",
                 __FILE__,__LINE__);
            return FAIL;
    }

    /* create property list. */
    create_plist = H5Pcreate(H5P_DATASET_CREATE);
    if(create_plist == -1) {
        H4toH5error_set(temph4toh5id,3,
                 "unable to create property list",
                 __FILE__,__LINE__);
        return FAIL;
    }
    if((c_flags == HDF_CHUNK) || (c_flags == (HDF_CHUNK|HDF_COMP))){
        if(ncomp == 1){
            chunk_dims[0] = (hsize_t)c_def_out.chunk_lengths[1]; 
            chunk_dims[1] = (hsize_t)c_def_out.chunk_lengths[0];
     
            if(H5Pset_chunk(create_plist, 2, chunk_dims)<0) {
                H4toH5error_set(temph4toh5id,3,
                     "unable to set up chunking information for property list",
                     __FILE__,__LINE__);
                H5Pclose(create_plist);
                return FAIL;    
            }
        }
        else if(ncomp ==3) {

            /* we want to make sure the dimensional order get changed later*/
            if(interlace_mode == MFGR_INTERLACE_PIXEL){
                chunk_dims24[0] = c_def_out.chunk_lengths[1]; 
                chunk_dims24[1] = c_def_out.chunk_lengths[0];
                chunk_dims24[2] = 3;
            }
            /* currently scan-line is not supported.
                    else if (interlace_mode == MFGR_INTERLACE_LINE){
                        chunk_dims24[0] = c_def_out.chunk_lengths[1]; 
                        chunk_dims24[2] = c_def_out.chunk_lengths[0];
                        chunk_dims24[1] = 3;
                    }
             */
            else if (interlace_mode == MFGR_INTERLACE_COMPONENT){
                chunk_dims24[1] = c_def_out.chunk_lengths[1]; 
                chunk_dims24[2] = c_def_out.chunk_lengths[0];
                chunk_dims24[0] = 3;
            }

            else {/* treat as pixel */
                chunk_dims24[0] = c_def_out.chunk_lengths[1]; 
                chunk_dims24[1] = c_def_out.chunk_lengths[0];
                chunk_dims24[2] = 3;
            }
             
            if(H5Pset_chunk(create_plist, 3, (hsize_t *)chunk_dims24)<0) {
                 H4toH5error_set(temph4toh5id,3,
                     "unable to set HDF5 chunking property list",
                     __FILE__,__LINE__);
                 H5Pclose(create_plist);
                 return FAIL;   
            }
        }

        if(c_flags == (HDF_CHUNK|HDF_COMP)) {
            if(comp_coder_type == COMP_CODE_RLE || comp_coder_type == COMP_CODE_SKPHUFF) {
                if(H5Zfilter_avail(H5Z_FILTER_DEFLATE) != 1) {
                    fprintf(stderr, "Deflate filter is not available in HDF5.  Writing without compression.\n");
                }
                else{
                    if(H5Pset_deflate(create_plist,H4H5_GZIP_COMLEVEL)<0){
                        H4toH5error_set(temph4toh5id,3,
                                                 "unable to set deflate compression",
                                         __FILE__,__LINE__);
                        H5Pclose(create_plist);
                        return FAIL;
                    }   
                }
            }
            else if(comp_coder_type == COMP_CODE_DEFLATE) {
                if(H5Zfilter_avail(H5Z_FILTER_DEFLATE) != 1) {
                    fprintf(stderr, "Deflate filter is not available in HDF5.  Writing without compression.\n");
                } 
                else {
                
                    gzip_level = c_info.deflate.level;
                    if(H5Pset_deflate(create_plist,gzip_level)<0){
                        H4toH5error_set(temph4toh5id,3,
                                    "unable to set deflate compression",
                                    __FILE__,__LINE__);
                        H5Pclose(create_plist);
                        return FAIL;
                    }
                }
            }
            else {
                H4toH5error_set(temph4toh5id,3,
                         "According to HDF4 reference manual, JPEG and szip compression are not supported with the chunking storage",
                        __FILE__,__LINE__);
                return FAIL;
            }
        }
    }
        
    else if(comp_coder_type != COMP_CODE_NONE) {
        if(ncomp == 1){
            chunk_dims[0] = (hsize_t)(image_dimsizes[1]);
            chunk_dims[1] = (hsize_t)(image_dimsizes[0]);
            
            if(H5Pset_chunk(create_plist, 2, chunk_dims)<0) {
                H4toH5error_set(temph4toh5id,3,
                "unable to set chunk property list",
                __FILE__,__LINE__);
                H5Pclose(create_plist);
                return FAIL;    
            }
        }
        else if(ncomp == 3) {
            
            /* we want to make sure the dimensional order get changed later*/
            
            if(interlace_mode == MFGR_INTERLACE_PIXEL){
                chunk_dims24[0] = (hsize_t)(image_dimsizes[1]); 
                chunk_dims24[1] = (hsize_t)(image_dimsizes[0]);
                chunk_dims24[2] = 3;
            }
            /* currently scan-line is not supported.
                     else if (interlace_mode == MFGR_INTERLACE_LINE){
                     chunk_dims24[0] = (hsize_t)(image_dimsizes[1]); 
                     chunk_dims24[2] = (hsize_t)(image_dimsizes[0]);
                     chunk_dims24[1] = 3;
                     }
            */
            else if (interlace_mode == MFGR_INTERLACE_COMPONENT){
                chunk_dims24[1] = (hsize_t)(image_dimsizes[1]); 
                chunk_dims24[2] = (hsize_t)(image_dimsizes[0]);
                chunk_dims24[0] = 3;
            }

            else {/* treat as pixel */
                chunk_dims24[0] = (hsize_t)(image_dimsizes[1]); 
                chunk_dims24[1] = (hsize_t)(image_dimsizes[0]);
                chunk_dims24[2] = 3;
            }
     
            if(H5Pset_chunk(create_plist, 3, chunk_dims24)<0) {
                H4toH5error_set(temph4toh5id,3,
                                    "unable to set chunk property list",
                                    __FILE__,__LINE__);
                H5Pclose(create_plist);
                return FAIL;    
            }
        }

        else {
                H4toH5error_set(temph4toh5id,3,
                                "HDF5 currently doesnot support component other than 1 or 3",
                                        __FILE__,__LINE__);
                H5Pclose(create_plist);
                return FAIL;
        }

        if(comp_coder_type == COMP_CODE_RLE || comp_coder_type == COMP_CODE_SKPHUFF 
                         || comp_coder_type == COMP_CODE_JPEG) {
            if(H5Zfilter_avail(H5Z_FILTER_DEFLATE) != 1) {
                fprintf(stderr, "Deflate filter is not available in HDF5.  Writing without compression.\n");
            }
            else{
                if(H5Pset_deflate(create_plist,H4H5_GZIP_COMLEVEL)<0){
                    H4toH5error_set(temph4toh5id,3,
                                         "unable to set deflate compression",
                                 __FILE__,__LINE__);
                    H5Pclose(create_plist);
                    return FAIL;
                }   
            }
        }
        else if(comp_coder_type == COMP_CODE_DEFLATE) {
            if(H5Zfilter_avail(H5Z_FILTER_DEFLATE) != 1) {
                                fprintf(stderr, "Deflate filter is not available in HDF5.  Writing without compression.\n");
            } 
            else {
                gzip_level = c_info.deflate.level;
                if(H5Pset_deflate(create_plist,gzip_level)<0){
                     H4toH5error_set(temph4toh5id,3,
                     "unable to set deflate compression",
                      __FILE__,__LINE__);
                     H5Pclose(create_plist);
                     return FAIL;
                }
            }
        }
        else if(comp_coder_type == COMP_CODE_SZIP) {

            unsigned int filter_config;
            /* SZIP is present.  Is it configured to be able to encode? */
            if(H5Zget_filter_info(H5Z_FILTER_SZIP, &filter_config) < 0)
            {
                H4toH5error_set(temph4toh5id,2,"unable to get HDF5 szip filter information",__FILE__,__LINE__);
                H5Pclose(create_plist);
                return FAIL;
            }

            if(! (filter_config & H5Z_FILTER_CONFIG_ENCODE_ENABLED))
            {
                fprintf(stderr, "szip configured without encoder in HDF5.  Writing without compression.\n");
            }
            else
            {
                szip_pixels_per_block = c_info.szip.pixels_per_block;
                options_mask = c_info.szip.options_mask;

                /* set szip compression parameters for HDF5 */
                if(H5Pset_szip(create_plist,options_mask,szip_pixels_per_block)<0) {
                    H4toH5error_set(temph4toh5id,3, 
                                 "unable to set up data creation property list for szip",
                                 __FILE__,__LINE__);
                    H5Pclose(create_plist);
                    return FAIL;
                }
            }
        }
    }
    return create_plist;
}

uint16 get_RIref(int32 file_id,uint16 tag,int32 image_ref)
{

    DFdi di;
    int32 found;
    int32 GroupID;
    uint16 ri_ref = 0;
    

    if((GroupID = DFdiread(file_id,tag,(uint16)image_ref))<0){
        /* for some cases, although sd_ref cannot be found, the current
             IMAGE object is still legal(unlimited dimension with the current
             size set to 0. so comment this the following warning printfs out. */
        /*      printf("cannot find sd_ref\n");*/
        return ri_ref;
    }

    found = 0;
    di.tag = DFTAG_NULL;
    di.ref = 0;
    while((found == 0) &&(DFdiget(GroupID,&di.tag,&di.ref)==0)){
        if(di.tag == DFTAG_RI || di.tag == DFTAG_RI8)
            found = 1;
    }

    ri_ref = (uint16)di.ref;
    /* comment out the following two lines. They are mostly for debugging purposes. */

    /*if(!found) ;*/
        /* printf("cannot find sd_ref\n");*/

    DFdifree(GroupID);
    return ri_ref;
}

/* vim:set ts=8 sw=2 sts=2 cindent: */
