/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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. 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 based HDF5 ID functions,users donot need to use this header file)

     H4TOH5Iprivate.h(private header file copied and modified based 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

2. this file 

including all routines that are useful for other files.

Author:  Kent Yang(myang6@hdfgroup.org)
 

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


#include "h4toh5util.h"


/**** h4toh5 utility functions. 
            PART I: General convenience functions. ******/
/* These functions are:
            1: h4toh5_ZeroMemory(zeroing out memory)

            2: mkstr(make HDF5 string type)

            3. conv_int_str(change integer to string)

            4: correct_name(correct the possible HDF object name
                 that includes "/" into "_".)

            5: get_groupname(get the full path of the parent group 
                 out of a full path of HDF5 objects.)

            6: trans_obj_name(make HDF4 attribute name out of 
                 object type plus ATTR plus reference number.)

                        7: make_objname_no(make absolute path name of HDF5 
                             object out of HDF4 object when the HDF4 object name 
                             is not defined.)

            8: make_objname_yes(make absolute path name of HDF5 object
                 out of HDF4 object when the HDF4 object name is defined.)
         
*/

/* Function h4toh5_ZeroMemory
     Purpose: Zero out memory
     return:    None
     In: size_t n(DWORD in windows)
            void* s(PVOID in windows)
*/


void h4toh5_ZeroMemory(void*s,size_t n) {
#ifdef WIN32
    ZeroMemory(s,n);
#else
    memset(s,0,n);
#endif
}


/*------------------------------------------------------------
 * Function:    mkstr
 *
 * Purpose:         make HDF5 string type
 *                          
 * Return:  type
 *
 * In :                 
             h4toh5id:  h4toh5 identifier
             size:            String Size
             H5T_str_t: pad
 
 *------------------------------------------------------------
 */ 

hid_t mkstr(hid_t  h4toh5id,
            size_t size, 
            H5T_str_t pad) {

    hid_t type; /* HDF5 data type id. */
    h4toh5id_t *dt; /* pointer to temporary h4toh5 id. */

    dt = H4TOH5I_object(h4toh5id);

    if((type=H5Tcopy(H5T_C_S1))<0) {
        H4toH5error_set(dt,3,"cannot make H5 String type",
             __FILE__,__LINE__);
        return -1;
    }
    if((H5Tset_size(type,size))<0) {
        H4toH5error_set(dt,3,"cannot set size for H5 String ",
             __FILE__,__LINE__);
        return -1;
    }
    if((H5Tset_strpad(type,pad))<0){
        H4toH5error_set(dt,3,"cannot set H5 String Pad",
             __FILE__,__LINE__);
        return -1;
    }
    return type;
}


/*---------------------------------------------------------------
 * Function:    conv_int_str
 *
 * Purpose: this function will convert numerical number into the 
                                string format for a reference.
 * Return:  SUCCEED if success, FAIL if failed.
    *
 * In :        num: an unsigned digital number.
               h4toh5id:  h4toh5 identifier
                                 
 * Out:        str_num: character string format of the number. 

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

int conv_int_str(hid_t h4toh5id,
         uint32 num, 
         char* str_num) {
     
    h4toh5id_t *dt; /* pointer to temporary h4toh5 id. */

    dt = H4TOH5I_object(h4toh5id);
    if(str_num == NULL) {
        H4toH5error_set(dt,1,"not enough memory for allocating str_num",
             __FILE__,__LINE__);
        return FAIL;
    }

    /*  Adding this line will cause problems, investigating this later.
            h4toh5_ZeroMemory(str_num,strlen(str_num)+1);*/
    sprintf(str_num,"%u",(unsigned int)num);
    return SUCCEED;
}


/*-----------------------------------------------------------------
 * Function:        correct_name
 *
 * Purpose:         modify the HDF4 object name when the name contains 
                                '/'. Change this character into '_'.
                                
 *                          
 * Return:          the corrected name
 *
 * In :             old name
                    h4toh5id:  h4toh5 identifier
 
 *-----------------------------------------------------------------
 */     
char *correct_name(hid_t h4toh5id, const char* oldname){

    char * cptr; /* temproary pointer that stores the address
                                    of the string where the ORI_SLASH is located. */
    char * newname; /* the new name after changing the ORI_SLASH to
                                         CHA_SLASH. */
    h4toh5id_t *dt; /* pointer to temporary h4toh5 id. */

#ifdef HAVE_LIBHDFEOS
    /* netCDF-4 is stricter. */
    if (H4toH5config_use_netcdf4_hack()) {
        return H4toH5correct_name_netcdf4(h4toh5id, oldname);
    }
#endif

    dt = H4TOH5I_object(h4toh5id);

    if(oldname == NULL) {
        H4toH5error_set(dt,5,"inputting name is wrong",
             __FILE__,__LINE__);
        return NULL;
    }

    newname = malloc(strlen(oldname)+1);
    if(newname == NULL) {
        H4toH5error_set(dt,1,"no enough memory for allocating newname",
             __FILE__,__LINE__);
        return NULL;
    }

    h4toh5_ZeroMemory(newname,strlen(oldname)+1);

    newname = strncpy(newname, oldname, strlen(oldname));
    while(strchr(newname,ORI_SLASH)!= NULL){
        cptr = strchr(newname,ORI_SLASH);
        *cptr = CHA_SLASH;
    }

    return newname;
}

/*------------------------------------------------------------------
 * Function:        get_groupname
 *
 * Purpose:         get the absolute path of the group from the absolute 
                                path of the HDF5 dataset
                                
 *                          
 * Return:          the absolute path of the group
 *
 * In :             the absolute path of the dataset
                    h4toh5id:  h4toh5 identifier
 
 *------------------------------------------------------------------
 */     
char *get_groupname(hid_t h4toh5id,char* datasetpath){

    char * cptr; /* temproary pointer that stores the address
                                    of the string where the ORI_SLASH is located. */
    char * groupname; /*the absolute group name. */
    h4toh5id_t *dt; /* pointer to temporary h4toh5 id. */

    dt = H4TOH5I_object(h4toh5id);
    if(datasetpath == NULL) {
        H4toH5error_set(dt,5,"inputting dataset path is NULL",
             __FILE__,__LINE__);
        return NULL;
    }

    /* find ORI_SLASH from the backward of datasetpath */
    cptr = strrchr(datasetpath,ORI_SLASH);
    if(cptr == NULL) {
        H4toH5error_set(dt,5,"datasetpath is not the absolute path or without /",
             __FILE__,__LINE__);
        return NULL;
    }

    groupname = malloc(cptr-datasetpath+1);
    if(groupname == NULL){
        H4toH5error_set(dt,1,"no enough memory to allocate groupname",
             __FILE__,__LINE__);
        return NULL;
    }
    strncpy(groupname,datasetpath,cptr-datasetpath+1);
    return groupname;
}

/*------------------------------------------------------------------
 * Function:    trans_obj_name
 *
 * Purpose:         make HDF4 attribute name 
                    The name will be HDF4 object type
                    plus ATTR plus reference number.
 *                          
 * Return:          object name;
 *
 * In :                 
        obj_tag:    HDF4 tag 
        index  :    HDF5 group id
        h4toh5id:  h4toh5 identifier
 
 *------------------------------------------------------------------
 */          
char* trans_obj_name(hid_t h4toh5id,
                 int32 obj_tag,
                 int32 h4toh5_index) {

    char* obj_name; /* the generated HDF5 object name */
    char indstr[MAXREF_LENGTH]; /* index string format converted from
                 decimal index */
    h4toh5id_t *dt;/* pointer to temporary h4toh5 id. */

    dt = H4TOH5I_object(h4toh5id);

    /* the reason why we allocate memory with strlen(HDF4_PALETTE) is 
         HDF4_PALETTE is the longest string among HDF4_??? 
         number 8 is chosen "arbitrarily", which assures the maximum number 
         for the object name. */
    obj_name = malloc(strlen(HDF4_PALETTE)+strlen(ATTR)+8);
    if(obj_name == NULL) {
        H4toH5error_set(dt,1,"cannot allocate memory for object name",
             __FILE__,__LINE__);
        return NULL;
    }

    h4toh5_ZeroMemory(obj_name,strlen(HDF4_PALETTE)+strlen(ATTR)+8);
    if(conv_int_str(h4toh5id,(uint32)h4toh5_index,indstr)== FAIL) {
        H4toH5error_set(dt,5,"cannot convert integer into string",
             __FILE__,__LINE__);
        return NULL;
    }

    /*find the appropriate object tag and make an object name. */

    switch(obj_tag) {

    case DFTAG_SD:
    case DFTAG_NDG:
    case DFTAG_SDG:
        strcpy(obj_name,HDF4_SDS);
        break;

    case DFTAG_RIG:
    case DFTAG_RI:
    case DFTAG_RI8:
        strcpy(obj_name,HDF4_IMAGE);
        break;

    case DFTAG_VG:
        strcpy(obj_name,HDF4_VGROUP);
        break;

    case DFTAG_VH:
    case DFTAG_VS:
        strcpy(obj_name,HDF4_VDATA);
        break;

    case DFTAG_LUT: 
        strcpy(obj_name,HDF4_PALETTE);
        break;

    default: 
        H4toH5error_set(dt,5,"object tag cannot be transferred ",
             __FILE__,__LINE__);
        free(obj_name);
        return NULL;
    }
        
    strcat(obj_name,"_");
    strcat(obj_name,ATTR);
    strcat(obj_name,"_");
    strcat(obj_name,indstr);

    return obj_name;
}

/*-------------------------------------------------------------------
 * Function:    make_objname_no
 *
 * Purpose:         make absolute path name of HDF5 object when object 
                                name is not defined. We will use path name and 
        object type(vgroup,SDS,image,palette, vdata) 
        plus reference number to make the new name unique.
 *                          
 * Return:  NULL if failed, object name if successful.
 *
 * In :                 
        h4toh5id:  h4toh5 identifier
        ref_str:     reference number in character format
        path_name: absolute path 
        objstr:      object type in character format
 
 *-------------------------------------------------------------------
 */ 

char* make_objname_no(hid_t h4toh5id,
                    char* refstr,
                    const char* path_name,
                    const char*objstr)
{

    char *new_objname; /* new object name */
    h4toh5id_t *dt; /* pointer to temporary h4toh5 id. */
    char * root_path;

    root_path =malloc(2);
    h4toh5_ZeroMemory(root_path,2);
    strcpy(root_path,"/");
    dt = H4TOH5I_object(h4toh5id);

    if(objstr == NULL || refstr == NULL) {
        H4toH5error_set(dt,5,"object type and ref. number should be defined.",
             __FILE__,__LINE__);
        return NULL;
    }

    if (path_name == NULL || strcmp(path_name,root_path) == 0) {/* under root group. */
            
        new_objname= malloc(strlen(objstr)+strlen(refstr)+3);
        if(new_objname == NULL) {
	    free(root_path);
            H4toH5error_set(dt,1,"cannot allocate memory for object name",
             __FILE__,__LINE__);
            return NULL;
        }
        h4toh5_ZeroMemory(new_objname,strlen(objstr)+strlen(refstr)+strlen(root_path)+1);
        strcpy(new_objname,root_path);
        strcat(new_objname,objstr);
        strcat(new_objname,"_");
        strcat(new_objname,refstr);
    }

    else {

        new_objname= malloc(strlen(path_name)+strlen(objstr)
            +strlen(refstr)+3);
        if(new_objname == NULL) {
	    free(root_path);
            H4toH5error_set(dt,3,"cannot allocate memory for new_objname",
             __FILE__,__LINE__);
            return NULL;
        }
        h4toh5_ZeroMemory(new_objname,strlen(path_name)+
                    strlen(objstr)+strlen(refstr)+3);
        strcpy(new_objname,path_name);
        strcat(new_objname,"/");
        strcat(new_objname,objstr);
        strcat(new_objname,"_");
        strcat(new_objname,refstr);
    }
    free(root_path);
    return new_objname;
}

/*-------------------------------------------------------------------
 * Function:    make_objname_yes
 *
 * Purpose:     get absolute path name of HDF5 object when object 
                name is defined. 
                             
 *                          
 * Return:  NULL if failed, object name if successful.
 *
 * In : obj_name: object name
        path_name: absolute path 
        h4toh5id:  h4toh5 identifier
 *-------------------------------------------------------------------
 */ 

char* make_objname_yes(hid_t h4toh5id,
                     char* obj_name,
                     const char* path_name){

    char*new_objname; /* new HDF5 object name */
    h4toh5id_t *dt; /* pointer to temporary h4toh5 id. */
    char* root_path; /* temporary variable to store root path "/" */
    dt = H4TOH5I_object(h4toh5id);

    root_path =malloc(2);
    h4toh5_ZeroMemory(root_path,2);
    strcpy(root_path,"/");

    if(path_name == NULL || strcmp(path_name,root_path) == 0) {
        /* under root group */
        new_objname = malloc(strlen(obj_name)+2);
        if(new_objname == NULL) {
             H4toH5error_set(dt,3,"cannot make H5 String type",
             __FILE__,__LINE__);
	    free(root_path);
            return NULL;
        }
        h4toh5_ZeroMemory(new_objname,strlen(obj_name)+2);
        strcpy(new_objname,root_path);
        strcat(new_objname,obj_name);
    }
    
    else {
        new_objname = malloc(strlen(path_name)+strlen(obj_name)+2);
        if(new_objname == NULL) {
            H4toH5error_set(dt,1,"cannot allocate enough memory for new_objname",
             __FILE__,__LINE__);
	    free(root_path);
            return NULL;
        }
        h4toh5_ZeroMemory(new_objname,strlen(path_name)
                    +strlen(obj_name)+2);
        strcpy(new_objname,path_name);
        strcat(new_objname,"/");
        strcat(new_objname,obj_name);
    }
    free(root_path);
    return new_objname;
}

/********** h4toh5 utility functions. *******************
            PART II: datatype conversion convenience functions. 
            These functions are:
                1. h5string_to_int(from HDF5 string type to integer)
    2. h4type_to_h5type(from HDF4 datatype to HDF5 datatype)
**********/

/*-------------------------------------------------------------------
 * Function:    h5string_to_int
 *
 * Purpose: This function will convert H5T_STRING into integer.
            This is a correction routine when the user defines the 
            numerical datatype int8 as DFNT_CHAR8 and DFNT_UCHAR8

 * Errors:  will return error message to the interface
 * Return:  FAIL if failed, SUCCEED if success
    *
 * In :     h4type: HDF4 datatype
            h4memsize: the real memory size of h4type
            h4toh5id:  h4toh5 identifier

 * Out:     h5memtype: pointer of which value should be h5memtype
                      (the real data type stored at the memory)
            h5type:      pointer of which value should be h5type
                       (the HDF5 type stored at the disk).
 *
 *--------------------------------------------------------------*/
        
    
int h5string_to_int(hid_t h4toh5id,
                const int32 h4type, 
                hid_t* h5memtype,
                const size_t h4memsize,
                hid_t* h5type) {

    h4toh5id_t *dt; /* pointer of the h4toh5 id handler. */

    dt = H4TOH5I_object(h4toh5id);

    switch(h4type) {

    case DFNT_CHAR8:

        *h5type = H5T_STD_I8BE;
        if (h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype = H5T_NATIVE_SCHAR;
        else if(h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
        else {
            H4toH5error_set(dt,5,"cannot convert HDF4 character into integer",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_UCHAR8:
         
        *h5type = H5T_STD_U8BE;
        if (h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_USHORT;
        else if(h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_UINT;
        else if(h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_ULONG;
        else {
            H4toH5error_set(dt,5,"cannot convert HDF4 character into integer",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;
    default:
	break;
    }
    return SUCCEED;
}
/*-------------------------------------------------------------------
 * Function:    H4toH5datatype
 *
 * Purpose: this is the public function that will convert HDF4 datatype 
            into HDF5 datatype.
            The conversion library includes file to file datatype and 
            datasize conversion, file to memory datatype and 
            datasize conversion. 

 * Errors:  will return error message to the interface.
 * Return:  false, FAIL. otherwise,SUCCEED.
 *
 * In :     h4type: HDF4 datatype
            h4toh5id:  h4toh5 identifier

 * Out:     h4sizeptr: pointer of which value is the file(disk) size of h4type. 
            h4memsizeptr: pointer of which value is the real memory size of h4type.
            h5memtype: pointer of which value should be h5memtype
                      (the real type stored at the memory).
            h5type:   pointer of which value should be h5type
                      (the HDF5 type that is stored at the disk).
 *           
 *
 *-----------------------------------------------------------------
 */ 
            
int  H4toH5datatype(hid_t       h4toh5id,
                const       int32 h4type, 
                hid_t*  h5typeptr,
                hid_t*  h5memtypeptr,
                size_t* h4sizeptr,
                size_t* h4memsizeptr){
    /* will wait for user's response to add more options*/
    return h4type_to_h5type(h4toh5id,h4type,h5memtypeptr,h4memsizeptr,
                h4sizeptr,h5typeptr);
}
/*-------------------------------------------------------------------
 * Function:    h4type_to_h5type
 *
 * Purpose: this function will convert HDF4 datatype into HDF5 datatype.
            The converter includes file to file datatype and 
            datasize conversion, file to memory datatype and 
            datasize conversion. 
            Check the mapping document for details.

 * Errors:          will return error message to the interface.
 * Return:  false, FAIL. otherwise,SUCCEED.
    *
 * In :     h4type: HDF4 datatype
            h4toh5id:  h4toh5 identifier

 * Out:     h4size: the file(disk) size of h4type.
            h4memsize: the real memory size of h4type.
 *          h5memtype: pointer of which value should be h5memtype
                      (the real type stored at the memory).
            h5type:      pointer of which value should be h5type
                      (the HDF5 type that is stored at the disk).
 *           
 *
 *-----------------------------------------------------------------
 */ 
            
int  h4type_to_h5type(hid_t h4toh5id,
                    const int32 h4type, 
                    hid_t* h5memtype,
                    size_t* h4memsize,
                    size_t* h4size, 
                    hid_t *h5type)
{

    h4toh5id_t *dt;/* pointer to h4toh5 id. */
    dt = H4TOH5I_object(h4toh5id);

    switch (h4type) {

    case DFNT_CHAR8:

        *h4size = 1;
        *h4memsize = sizeof(int8);
        /* assume DFNT_CHAR8 C type character. */
        *h5memtype = H5T_STRING;
        *h5type =  H5T_STRING;
        break;

    case DFNT_UCHAR8:

        *h4size = 1;
        *h4memsize = sizeof(int8);
        *h5memtype = H5T_STRING;
        *h5type = H5T_STRING;
        break;

    case DFNT_INT8:

        *h4size = 1;
        *h5type = H5T_STD_I8BE;
        *h4memsize = sizeof(int8);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype = H5T_NATIVE_SCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
        else {
             H4toH5error_set(dt,5,"cannot convert signed INT8",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_UINT8:

        *h4size =1;
        *h5type = H5T_STD_U8BE;
        *h4memsize = sizeof(int8);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_USHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_UINT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_ULONG;
        else {
             H4toH5error_set(dt,5,"cannot convert unsigned INT8",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_NINT8:
        /*printf("warning, Native HDF datatype is encountered");
        printf(" the converting result may not be correct.\n");*/
        *h4size = 1;
        *h5type = H5T_NATIVE_SCHAR;
        *h4memsize = sizeof(int8);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_SCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
        else {
             H4toH5error_set(dt,5,"cannot convert native INT8",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_NUINT8:
        /*printf("warning, Native HDF datatype is encountered");
        printf(" the converting result may not be correct.\n");*/
        *h4size = 1;
        *h5type = H5T_NATIVE_UCHAR;
        *h4memsize = sizeof(int8);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
        else {
             H4toH5error_set(dt,5,"cannot convert unsighed naive INT8 ",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_LINT8:
        *h4size = 1;
        *h5type = H5T_STD_I8LE;
        *h4memsize = sizeof(int8);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
        else {
            
             H4toH5error_set(dt,5,"cannot convert little-endian INT8",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_LUINT8:
        *h4size = 1;
        *h5type = H5T_STD_U8LE;
        *h4memsize = sizeof(int8);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_USHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_UINT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_ULONG;
        else {
             H4toH5error_set(dt,5,"cannot convert little-endian unsigned INT8",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_INT16:
        *h4size = 2;
        *h5type = H5T_STD_I16BE;
        *h4memsize = sizeof(int16);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_CHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
        else {
            H4toH5error_set(dt,5,"cannot convert signed int16",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_UINT16:
        *h4size = 2;
        *h5type = H5T_STD_U16BE;
        *h4memsize = sizeof(int16);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_USHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_UINT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_ULONG;
        else {
            H4toH5error_set(dt,5,"cannot convert unsigned int16",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_NINT16:
        *h4size = 2;
        *h5type = H5T_NATIVE_SHORT;
        *h4memsize = sizeof(int16);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_CHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
        else {
            H4toH5error_set(dt,5,"cannot convert native int16",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_NUINT16:
        *h4size = 2;
        *h5type = H5T_NATIVE_USHORT;
        *h4memsize = sizeof(int16);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_USHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_UINT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_ULONG;
        else {
            H4toH5error_set(dt,5,"cannot convert unsigned native int16",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_LINT16:
        *h4size = 2;
        *h5type = H5T_STD_I16LE;
        *h4memsize = sizeof(int16);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
        else {
            H4toH5error_set(dt,5,"cannot convert little-endian int16",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_LUINT16:
        *h4size = 2;
        *h5type = H5T_STD_U16LE;
        *h4memsize = sizeof(int16);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_USHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_UINT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_ULONG;
        else {
            H4toH5error_set(dt,5,"cannot convert little-endian unsigned int16",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_INT32:
        *h4size = 4;
        *h5type = H5T_STD_I32BE;
        *h4memsize = sizeof(int32);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_CHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
        else {
            H4toH5error_set(dt,5,"cannot convert signed int32",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_UINT32:
        *h4size = 4;
        *h5type = H5T_STD_U32BE;
        *h4memsize = sizeof(int32);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_USHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_UINT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_ULONG;
        else {
             H4toH5error_set(dt,5,"cannot convert unsigned int32",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_NINT32:
        *h4size = 4;
        *h5type = H5T_NATIVE_INT;
        *h4memsize = sizeof(int32);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_CHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
        else {
             H4toH5error_set(dt,5,"cannot convert native signed int32",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_NUINT32:
        *h4size =4;
        *h5type = H5T_NATIVE_UINT;
        *h4memsize = sizeof(int32);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_USHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_UINT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_ULONG;
        else {
             H4toH5error_set(dt,5,"cannot convert signed int32",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_LINT32:
        *h4size =4;
        *h5type = H5T_STD_I32LE;
        *h4memsize = sizeof(int32);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_CHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
        else {
             H4toH5error_set(dt,5,"cannot convert little-endian signed int32",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_LUINT32:
        *h4size =4;
        *h5type = H5T_STD_U32LE;
        *h4memsize = sizeof(int32);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_USHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_UINT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_ULONG;
        else {
            H4toH5error_set(dt,5,"cannot convert little-endian unsigned int32",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_INT64:
        *h4size = 8;
        *h5type = H5T_STD_I64BE;
        *h4memsize = sizeof(long);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_CHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LLONG))
            *h5memtype = H5T_NATIVE_LLONG;
        else {
            H4toH5error_set(dt,5,"cannot convert signed int64",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_UINT64:
        *h4size = 8;
        *h5type = H5T_STD_U64BE;
        *h4memsize = sizeof(long);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_USHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_UINT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_ULONG;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LLONG))
            *h5memtype = H5T_NATIVE_ULLONG;
        else {
             H4toH5error_set(dt,5,"cannot convert unsigned int64",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_NINT64:
        *h4size = 8;
        *h5type = H5T_NATIVE_INT;
        *h4memsize = sizeof(long);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_CHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LLONG))
            *h5memtype = H5T_NATIVE_LLONG;
        else {
             H4toH5error_set(dt,5,"cannot convert native signed int64",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_NUINT64:
        *h4size =8;
        *h5type = H5T_NATIVE_UINT;
        *h4memsize = sizeof(long);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_USHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_UINT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_ULONG;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LLONG))
            *h5memtype = H5T_NATIVE_ULLONG;
        else {
             H4toH5error_set(dt,5,"cannot convert signed int64",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_LINT64:
        *h4size =8;
        *h5type = H5T_STD_I64LE;
        *h4memsize = sizeof(long);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_CHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_SHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_INT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_LONG;
         else if(*h4memsize == H5Tget_size(H5T_NATIVE_LLONG))
            *h5memtype = H5T_NATIVE_LLONG;
        else {
             H4toH5error_set(dt,5,"cannot convert little-endian signed int64",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_LUINT64:
        *h4size =8;
        *h5type = H5T_STD_U64LE;
        *h4memsize = sizeof(long);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_CHAR))
            *h5memtype =    H5T_NATIVE_UCHAR;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_SHORT))
            *h5memtype = H5T_NATIVE_USHORT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_INT))
            *h5memtype = H5T_NATIVE_UINT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LONG))
            *h5memtype = H5T_NATIVE_ULONG;
         else if(*h4memsize == H5Tget_size(H5T_NATIVE_LLONG))
            *h5memtype = H5T_NATIVE_ULLONG;
        else {
            H4toH5error_set(dt,5,"cannot convert little-endian unsigned int64",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_FLOAT32:
        *h4size =4;
        *h5type = H5T_IEEE_F32BE;
        *h4memsize = sizeof(float32);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_FLOAT))
            *h5memtype = H5T_NATIVE_FLOAT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_DOUBLE))
            *h5memtype = H5T_NATIVE_DOUBLE;
        else {
            H4toH5error_set(dt,5,"cannot convert float32",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;
    
    case DFNT_FLOAT64:
        *h4size = 8;
        *h5type = H5T_IEEE_F64BE;
        *h4memsize = sizeof(float64);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_FLOAT))
            *h5memtype = H5T_NATIVE_FLOAT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_DOUBLE))
            *h5memtype = H5T_NATIVE_DOUBLE;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LDOUBLE))
            *h5memtype = H5T_NATIVE_LDOUBLE;
        else {
            H4toH5error_set(dt,5,"cannot convert float64",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_NFLOAT32:
        *h4size = 4;
        *h5type = H5T_NATIVE_FLOAT;
        *h4memsize = sizeof(float32);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_FLOAT))
            *h5memtype = H5T_NATIVE_FLOAT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_DOUBLE))
            *h5memtype = H5T_NATIVE_DOUBLE;
        else {
             H4toH5error_set(dt,5,"cannot convert native float32",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_NFLOAT64:
        *h4size = 8;
        *h5type = H5T_NATIVE_DOUBLE;
        *h4memsize = sizeof(float64);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_FLOAT))
            *h5memtype = H5T_NATIVE_FLOAT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_DOUBLE))
            *h5memtype = H5T_NATIVE_DOUBLE;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LDOUBLE))
            *h5memtype = H5T_NATIVE_LDOUBLE;
        else {
             H4toH5error_set(dt,5,"cannot convert native float64",
             __FILE__,__LINE__);
            return FAIL;    
        }
        break;

    case DFNT_LFLOAT32:
        *h4size = 4;
        *h5type = H5T_IEEE_F32LE;
        *h4memsize = sizeof(float32);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_FLOAT))
            *h5memtype = H5T_NATIVE_FLOAT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_DOUBLE))
            *h5memtype = H5T_NATIVE_DOUBLE;
        else {
             H4toH5error_set(dt,5,"cannot convert little-endian float32",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

    case DFNT_LFLOAT64:
        *h4size = 8;
        *h5type = H5T_IEEE_F64LE;
        *h4memsize = sizeof(float64);
        if(*h4memsize == H5Tget_size(H5T_NATIVE_FLOAT))
            *h5memtype = H5T_NATIVE_FLOAT;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_DOUBLE))
            *h5memtype = H5T_NATIVE_DOUBLE;
        else if(*h4memsize == H5Tget_size(H5T_NATIVE_LDOUBLE))
            *h5memtype = H5T_NATIVE_LDOUBLE;
        else {
            H4toH5error_set(dt,5,"cannot convert little-endian float64",
             __FILE__,__LINE__);
            return FAIL;
        }
        break;

        default: {
             H4toH5error_set(dt,4,"cannot find the corresponding datatype in HDF5",
             __FILE__,__LINE__);
        
        return FAIL;
        }
    }
    return SUCCEED;
}

/********** h4toh5 utility functions. *******************
            PART III: HDF4 to HDF5 specific attribute  conversion 
            convenience functions. These attributes are not real attributes
            of HDF4 object; but some appendix information while doing
            HDF4 to HDF5 conversions. Please see h4toh5 mapping document
            for details.
            These functions are:
                1. h4_transnumattr
    (convert object reference number into an HDF5 attribute)
    2. h4_transpredattrs
                (convert predefined HDF4 information such as HDF4 OBJECT NAME,
    HDF4 OBJECT TYPE or HDF4 OBJECT CLASS; they should all
    be converted into HDF5 string.) 
**********/

/*-------------------------------------------------------------------
 * Function:    h4_transnumattr
 *
 * Purpose:     translate HDF4 object reference number into an HDF5 attribute
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h5g: HDF5 group id
        refname: reference name
        group_ref: HDF4 reference number
        h4toh5id:  h4toh5 identifier
 
 *----------------------------------------------------------------
*/
        
int h4_transnumattr(hid_t h4toh5id, 
                hid_t h5g,
                const char *refname,
                uint16 group_ref) {

    hid_t        h5memtype; /* HDF5 memory data type. */
    hid_t        h5a_id; /* HDF5 attribute id */
    hid_t        h5a_sid; /* HDF5 attribute space id. */
    herr_t   ret; /* variable to check HDF5 "return" status */
    h4toh5id_t *dt; /* pointer to h4toh5 id */

    dt = H4TOH5I_object(h4toh5id);

    if (H4toH5config_use_netcdf4_hack()) {
        /* netCDF4 cannot read reference types and raises error */
        if (strcmp(refname, HDF4_REF_NUM) == 0)
            return SUCCEED;
    }

    /* create attribute space id and attribute id */
    h5a_sid = H5Screate(H5S_SCALAR);

    if (h5a_sid < 0) {
        H4toH5error_set(dt,3,"cannot create attribute space for HDF4_REF_NUM",
             __FILE__,__LINE__);
        return FAIL;
    }

    h5a_id = H5Acreate_safe(h4toh5id,h5g,refname,H5T_STD_U16BE,h5a_sid,H5P_DEFAULT);
    if(h5a_id <0) {
         H4toH5error_set(dt,3,"cannot create attribute id for HDF4_REF_NUM",
             __FILE__,__LINE__);
        H5Sclose(h5a_sid);
        return FAIL;
    }

    /* data type conversion from HDF4 uint16 to HDF5 */
    if(H5Tget_size(H5T_NATIVE_CHAR)== sizeof(uint16))
        h5memtype =  H5T_NATIVE_UCHAR;
    else if(H5Tget_size(H5T_NATIVE_SHORT)== sizeof(uint16))
        h5memtype = H5T_NATIVE_USHORT;
    else if(H5Tget_size(H5T_NATIVE_INT) == sizeof(uint16))
        h5memtype = H5T_NATIVE_UINT;
    else if(H5Tget_size(H5T_NATIVE_LONG)== sizeof(uint16))
        h5memtype = H5T_NATIVE_ULONG;
    else {
        H5Sclose(h5a_sid);
        H5Aclose(h5a_id);
        return FAIL;
    }

    ret = H5Awrite(h5a_id,h5memtype,(void *)&group_ref);

    if(ret <0) {
        H4toH5error_set(dt,3,"cannot write attribute",
             __FILE__,__LINE__);
        H5Sclose(h5a_sid);
        H5Aclose(h5a_id);
        return FAIL;
    }

    ret = H5Sclose(h5a_sid);
    if( ret < 0) {
        H4toH5error_set(dt,3,"cannot close HDF5 data space ",
             __FILE__,__LINE__);
        H5Aclose(h5a_id);
        return FAIL;
    }

    ret = H5Aclose(h5a_id);
    if(ret < 0) {
        H4toH5error_set(dt,3,"cannot close HDF5 attribute id ",
             __FILE__,__LINE__);
        return FAIL;
    }

    return SUCCEED;
}


/*-----------------------------------------------------------------
 * Function:    h4_transpredattrs
 *
 * Purpose:     translate predefined attributes into HDF5 attribute
 *              predefined attributes including HDF4 OBJECT TYPE, 
                HDF4 OBJECT NAME, HDF4 CLASS etc. They are all in
                H5T_STRING format.

 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5id:  h4toh5 identifier
        h5g: group id
        attrname: attribute name
        data: attribute data
 
 *-----------------------------------------------------------------
*/       
int h4_transpredattrs(hid_t h4toh5id,
                    hid_t h5g,
                    const char *attrname,
                    char* data){

    size_t   h5str_size; /* HDF5 string size */
    hid_t           h5a_id; /* HDF5 attribute id */
    hid_t           h5a_sid; /* HDF5 attribute space id */
    hid_t           h5str_type; /* HDF5 string type */
    herr_t      ret; /* temporary variable to check the "return" status of HDF5 */
    h4toh5id_t *dt;/* pointer to temporary h4toh5 id. */

    dt = H4TOH5I_object(h4toh5id);
    if(data == NULL) {
         H4toH5error_set(dt,2,"predefined attribute data is not available",
             __FILE__,__LINE__);
        return FAIL;
    }

    h5str_size = strlen(data);
    if ((h5str_type = mkstr(h4toh5id,h5str_size,H5T_STR_NULLTERM))<0) {
         H4toH5error_set(dt,3,"cannot make H5 String type for h4 predefined attribute",
             __FILE__,__LINE__);
        return FAIL;
    }

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

    h5a_id = H5Acreate_safe(h4toh5id,h5g,attrname,h5str_type,h5a_sid,H5P_DEFAULT);
    if(h5a_id <0) {
         H4toH5error_set(dt,3,"cannot create attribute",
             __FILE__,__LINE__);
        H5Sclose(h5a_sid);
        return FAIL;
    }

    ret = H5Awrite(h5a_id,h5str_type,(void *)data);
    if(ret <0) {
         H4toH5error_set(dt,3,"cannot write attribute",
             __FILE__,__LINE__);
        H5Aclose(h5a_id);
        H5Sclose(h5a_sid);
        return FAIL;
    }
    ret = H5Sclose(h5a_sid);
    if (ret < 0) {
        H4toH5error_set(dt,3,"cannot close data space id",
             __FILE__,__LINE__);
        H5Aclose(h5a_id);
        return FAIL;
    }
    ret = H5Aclose(h5a_id);
    if (ret < 0) {
        H4toH5error_set(dt,3,"cannot close attribute interface",
             __FILE__,__LINE__);
        return FAIL;
    }
    return SUCCEED;
}


/********** h4toh5 utility functions. *******************
            PART IV: table management functions
            Since we have three tables, we will break them into three
            subparts: (1) table (2) name table (3) modname table            
*********************/

/*********** We create three kinds of hash tables. 

        1. reference hash table: object reference as the key.
        fuctions: lookup,set_name,get_name
        lookup  are used for checking whether HDF4 objects 
        are touched or not.
        set_name and get_name will append or obtain 
        the name based on the lookup function.
        Objects used by this function: SDS,image,vdata,
        vgroup,palette

        2. name hash table: name as the key, has its own hash 
           function
        functions: lookup_updatename, hashfun 
        lookup_updatename will append the name after 
        it search the table and cannot find the name. 
        lookup_updatename will be used in the library API to
        check whether the dataset or group names are used 
        or not. 

        3. modname hash table: It was used in the converter to 
           deal with SDS dimensional scale dataset. Since dim. name 
        is unique for SDS dimensional scale dataset, so the name
        for SDS dimensional scale dataset is used for the
        object key.
        For h4toh5 library APIs, since we allow users to provide 
        their own dimensional scale dataset names; so we have
        to create another element in this table to append 
        the absolute path of the first touched SDS 
        dimensional scale dataset name. Once we found this name was
        looked up already, we would like to create a hardlink from
        the current dim. scale to the original dim. scale.
                 
***********************************/

/********IV.(1) table used object reference as the key
            These functions are:
        1. lookup
        (use object reference as the key to check whether the table
         is looked up or not)
        2. get_name
        (obtain the name of the object according to the object
         reference)
        3. set_name
        (store the name of the object into the reference table) 
**********/


/*----------------------------------------------------------------
 * Function:    lookup
 *
 * Purpose: this function will use objref as a key to check 
                                whether the current object is touched.

 * Return:  1,  the object is found.
            0,  the object is not found.
           -1, the table doesn't exist.
 *
 * In :                 
        h4toh5id:  h4toh5 identifier
        objref:      reference number of the current object.
        SIZE:            size of the reference hashtable.
        hashtab:     pointer to the reference hash table.
        group_flagptr: pointer of the group_flag;
        this flag is specifically used to trace vgroup flag.
        (1.when vgroup flag is set to 0 for converting vgroup A,
             only pure vgroup A is converted to corresponding HDF5 group.
             No member is converted. This flag is stored in the *hashtab*.
         2.vgroup flag is then set to 1 for converting vgroup A with 
             all its members,
             the vgroup flag will be used to compare with the flag stored
             in the *hashtab* and if it is different, members of 
             vgroupA is converted and a hardlink is generated.
             see comments for h4toh5basvgroup.)

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

int lookup(hid_t h4toh5id,
         int objref,
         int SIZE,
         struct table*hashtab,
         int* group_flagptr) {

    /* If we don't care about the flag, 
         just set group_flagptr to NULL. */

    int temp_flag; /* temporary flag */
    h4toh5id_t *dt; /* pointer to h4toh5 id for error handlings */
    struct table *np; /*pointer to the temporary hash table */

    dt = H4TOH5I_object(h4toh5id);

    if(hashtab == NULL) {
        H4toH5error_set(dt,4,"the table doesn't exist",
             __FILE__,__LINE__);
        return -1;
    }

    /* look through this bucket. */
    for (np = hashtab+objref%SIZE; np!=NULL;np=np->next){
        if (np->ref == objref){
            if(group_flagptr == NULL) {
                return 1;
            }
 
            /* temp_flag brings in the current flag.
             *group_flagptr should be assigned to the original(previous) vg_flag.
                This part is used for h4toh5basvgroup conversion function.*/
            temp_flag =*group_flagptr;
            *group_flagptr= np->flag;
            if(temp_flag > np->flag) 
                np->flag = temp_flag;
            return 1;
        }
    }
    return 0;
}

/*-------------------------------------------------------------------
 * Function:    get_name
 *
 * Purpose:         obtain the name of the object from reference hash 
                                table
 *                          
 * Return:  the object name 
 *
 * In :     h4toh5id:  h4toh5 identifier
            objref: reference number of the current object.
            SIZE:       the hashtable SIZE.
        hashtab: pointer to the hash table
        pcheck_get: a flag to check errors
 
 *-------------------------------------------------------------------
 */             

char* get_name(hid_t h4toh5id, 
                 int objref,
                 int SIZE,
                 struct table*hashtab, 
                 int* pcheck_get) {

    struct table *np; /* temporary hashtable pointer. */
    char* tempname; /* temporary name */
    h4toh5id_t *dt; /* pointer to h4toh5 id */

    dt = H4TOH5I_object(h4toh5id);

    for (np = hashtab+objref%SIZE; np!=NULL;np=np->next){
        /* find the right object */
        if (np->ref==objref){
            if (np->name == NULL) {
                *pcheck_get = -1;
                H4toH5error_set(dt,4,"no name is found for this object",
                                      __FILE__,__LINE__);
                return NULL;
            }
            else {
                tempname = malloc(strlen(np->name)+1);
                if (tempname == NULL) {
                    *pcheck_get = -2;
                    H4toH5error_set(dt,1,"no enough memory is set for this object",
                             __FILE__,__LINE__);
                    return NULL;
                }
                strcpy(tempname,np->name);
                return tempname;
            }
        }
    }

    /* not find the right object , return NULL but with the checker as
         0. */
    *pcheck_get = 0;
    return NULL;
}

/* A routine to support the use of HDF5 dimension scale APIs. */
/*-------------------------------------------------------------------
 * Function:        lookup_len_update_name
 *
 * Purpose:         Check if the size of the fake dimension(cur_len) matches the size in
                                the hashtab. If it matches, returns the corresponding name.
                                If no, returns NULL. 
 *                          
 * Return:  Return the corresponding name or NULL. 
                                The caller should free the memory of the returned name.
 *
 * In : h4toh5id:  h4toh5 interface identifier
        cur_len:     The length associated with the current object(fake dimension size)
        obj_tab:     pointer to the object table(used to handle SDS fake dimensions)
        cur_name:  Current object name(fake dimension name)
        err_ptr:     pointer to a flag that checks errors
 * Out:                 pointer to check the error flag(value pointed to will be -1 if an error occur)
 *-------------------------------------------------------------------
 */             

char* lookup_len_update_name(hid_t h4toh5id,
                             int cur_len,
                             struct table*obj_tab,
                             const char* cur_name,
                             short* err_ptr ) {

    struct table *tab_ptr       = NULL; /* obj_table pointer. */
    struct table *temptr        = NULL; /*temporary table pointer */

    char* tempname                  = NULL; /* temporary obj name,will return  */
    h4toh5id_t *h4toh5id_ptr= NULL; /* pointer to h4toh5 id */

    short find_cur_name             = 0; /* flag to check if the name is found */

    /* Obtain pointer to h4toh5id; this is for error handling*/
    h4toh5id_ptr = H4TOH5I_object(h4toh5id);

    /* Loop through the table to see if the current length matches to any length in the current cell.
         If yes, mark the find_cur_name flag and obtain the name.*/
    for(tab_ptr = obj_tab; tab_ptr!= NULL;tab_ptr = tab_ptr->next) {

        if (tab_ptr->ref==cur_len){

            /* If we find the length in the cell, there should be the corresponding name. */
            if (tab_ptr->name == NULL) {
                *err_ptr = -1;
                H4toH5error_set(h4toh5id_ptr,4,"no name is found for this object",
                                                               __FILE__,__LINE__);
                break;
            }
            else { /* Find the name, mark the flag.*/
                tempname = malloc(strlen(tab_ptr->name)+1);
                if (tempname == NULL) {
                    *err_ptr = -1;
                    H4toH5error_set(h4toh5id_ptr,1,"no enough memory is set for this object",
                                                                        __FILE__,__LINE__);
                    break;
                }
                strcpy(tempname,tab_ptr->name);
                find_cur_name = 1;
                break;
            }
        }
    }
    /* If not finding the name, create a new cell with the cur_name and cur_len,
         insert the cell to the table. */
    if(find_cur_name == 0) {
        for(tab_ptr = obj_tab; tab_ptr!= NULL;tab_ptr = tab_ptr->next) {
            if (tab_ptr->next == NULL) {
                temptr=malloc(sizeof(struct table));
                if (temptr == NULL) {
                    *err_ptr = -1;
                    H4toH5error_set(h4toh5id_ptr,1,"no enough memory is set for this table",
                                                                           __FILE__,__LINE__);
                    break;
                }
                tab_ptr->next = temptr;
                temptr->next = NULL;
                temptr->ref = cur_len;
                temptr->flag = -1;
                temptr->name = malloc(strlen(cur_name)+1);
                if (temptr->name == NULL) {
                     *err_ptr = -1;
                     H4toH5error_set(h4toh5id_ptr,1,"no enough memory is set for this object name",
                                                                                 __FILE__,__LINE__);
                     break;
                }
                strcpy(temptr->name,cur_name);
                break;
            }
        }
    }

    return tempname;
}

/* End of the routine to support the use of HDF5 dimension scale APIs. */

/*-----------------------------------------------------------------
 * Function:    set_name
 *
 * Purpose:     store the name of the object into the reference 
                hash table.
                The hash table is also updated.
 *                          
 * Return:  SUCCEED: the name is either set before or set in 
                     this routine
 *          FAIL:  the name is not set properly      
 *
 * In : h4toh5id:  h4toh5 identifier
        objref: reference number of the current object
        SIZE:       the hashtable SIZE
        hashtab: reference hash table
        namein: object name
        vg_flag: a flag to trace whether the conversion
                 occurs for the pure vgroup or the non-vgroup
                 members of this vgroup.
 *----------------------------------------------------------------*/
            


int set_name(hid_t h4toh5id, 
             int objref,
             int SIZE,
             struct table*hashtab, 
             char* namein,
             int vg_flag) {

    struct table *np; /* temporary hashtable pointer. */
    struct table *temptr; /* another temporary hashtable pointer to store
                                                     the bucket */
    h4toh5id_t *dt; /* pointer to h4toh5 id. */
    dt = H4TOH5I_object(h4toh5id);

    temptr = malloc(sizeof(struct table));
    if(temptr == NULL) {
        H4toH5error_set(dt,1,"not enough memory to be allocated.",
             __FILE__,__LINE__);
        return FAIL;
    }

    for (np = hashtab+objref%SIZE; np!= NULL;np = np->next){
        if (np->ref==objref){
            /* the name is set already, don't do anything.*/
            return SUCCEED;
        }
        /* ADD THE name in */
        if (np->next == NULL) {
            np->next = temptr;
            temptr->ref = objref;
            temptr->next = NULL;
            if(namein == NULL) 
                temptr->name = NULL;
            else {
                temptr->name = malloc(strlen(namein)+1);
                if(temptr->name == NULL) {
                    H4toH5error_set(dt,1,"not enough memory to be allocated.",
                             __FILE__,__LINE__);
                    return FAIL;
                }
                strcpy(temptr->name,namein);
            }
            temptr->flag = vg_flag;
            return SUCCEED;
        }
    }
    return SUCCEED;
}

/*-----------------------------------------------------------------
 * Function:    init_tab
 *
 * Purpose: this function will initialize the reference 
                                hash table.
 *                       

 * Return:  SUCCEED, table is initialzed. FAIL,otherwise.
 *
 * In : h4toh5id:  h4toh5 identifier
        SIZE:       the hashtable SIZE.
        hashtab: pointer to the hash table.
 
 *------------------------------------------------------------------
 */ 

int init_tab(hid_t h4toh5id, 
             int SIZE,
             struct table *hashtab) {

    int i; /* temporary index */
    h4toh5id_t *dt;/* pointer to temporary h4toh5 id. */
    dt = H4TOH5I_object(h4toh5id);

    if(hashtab == NULL) {
        H4toH5error_set(dt,1,"No enough memory to allocate the table",
             __FILE__,__LINE__);
        return FAIL;
    }
    for (i = 0;i < SIZE; i++) {
        (hashtab+i%SIZE)->ref  = -1;
        (hashtab+i%SIZE)->next = NULL;
        (hashtab+i%SIZE)->name = NULL;
        (hashtab+i%SIZE)->flag = -1;
    }
    return SUCCEED;
}

/*-----------------------------------------------------------------
 * Function:    init_tab2
 *
 * Purpose: this function will initialize the reference 
                                hash table.
 *                       

 * Return:  SUCCEED, table is initialzed. FAIL,otherwise.
 *
 * In : h4toh5id:  h4toh5 identifier
        SIZE:       the hashtable SIZE.
        hashtab: pointer to the hash table.
 
 *------------------------------------------------------------------
 */ 

int init_tab2(hid_t h4toh5id, 
             struct table *hashtab) {

    h4toh5id_t *dt;/* pointer to temporary h4toh5 id. */
    dt = H4TOH5I_object(h4toh5id);

    if(hashtab == NULL) {
        H4toH5error_set(dt,1,"No enough memory to allocate the table",
             __FILE__,__LINE__);
        return FAIL;
    }
    hashtab->ref    = -1;
    hashtab->next = NULL;
    hashtab->name = NULL;
    hashtab->flag = -1;
    
    return SUCCEED;
}

/*----------------------------------------------------------------
 * Function:    freetable
 *
 * Purpose:     free the memory of hash table 
 *                          
 * Return:  0
 *
 * In :   h4toh5id:  h4toh5 identifier
          SIZE:       the hashtable SIZE.
          nametab: hash table 
 
 *------------------------------------------------------------------
 */ 
int freetable(int SIZE,struct table *hashtab) {

    struct table *np; /* the hashtable pointer */
    struct table *temptr; /* the temporary hashtable pointer to store
                                                     deleted hash table. */
    struct table *temptr1; /* another temporary hashtable pointer to 
                                                        store the deleted hash table. */
    int i; /* the temporary index variable for the for loop. */

    if(hashtab == NULL) return 0; 

    /* we first free the additional linked items of the hashtable,
         and then free the whole hash table. */
    for (i =0;i < SIZE; i++) {
        np = hashtab+i;
        temptr1 = np->next;
        while(temptr1 != NULL) {
            temptr = temptr1;
            temptr1 = temptr1->next;
            if(temptr->name != NULL) 
                free(temptr->name);
            free(temptr);
        }
        if(np->name != NULL) 
            free(np->name);
    }

    free(hashtab);
    return 0;
}
/*----------------------------------------------------------------
 * Function:    freetable2
 *
 * Purpose:    free the memory of the table 
 *                          
 * Return:  0
 *
 * In : h4toh5id:  h4toh5 identifier
        nametab: hash table 
 
 *------------------------------------------------------------------
 */ 
int freetable2(struct table *hashtab) {

    struct table *temptr; /* the temporary hashtable pointer to store
                                                     deleted hash table. */
    struct table *temptr1; /* another temporary hashtable pointer to 
                                                        store the deleted hash table. */

    if(hashtab == NULL) return 0; 

    /* we first free the additional linked items of the hashtable,
         and then free the whole hash table. */
    temptr1 = hashtab->next;
    while(temptr1 != NULL) {
        temptr = temptr1;
        temptr1 = temptr1->next;
        if(temptr->name != NULL) 
            free(temptr->name);
        free(temptr);
    }
    if(hashtab->name != NULL) 
        free(hashtab->name);

    free(hashtab);
    return 0;
}

/********IV(2) table used object name as the key
            These functions are:
                1. hash_fun
                2. lookup_updatename
    (use name as the key to check whether the table
    is looked up or not)
    
**********/
/*------------------------------------------------------------------
 * Function:    hash_fun
 *
 * Purpose:         to get the hash value based on the key 
 *                          
 * Return:  No. of the hashtable 
 *
 * In :     name:       object name 
            size:       the hashtable size.
     
 *------------------------------------------------------------------
 */ 
int hash_fun(const char *name,int size) {

    int hashval; /* hashtable value */

    for (hashval = 0;*name !='\0';)
        hashval += *name++;
    return(hashval%size); 

}
/*-------------------------------------------------------------------
 * Function:    lookup_name
 *
 * Purpose:     look up whether the same name is used for 
                                     different objects 
                            
 *                          
 * Return:  1, if the name is in the name hash table.
            0, if the name is not in the name table.
            -1, otherwise.
 *
 * In : h4toh5id:  h4toh5 identifier
        size:       the hashtable SIZE.
        nametab: name hash table
        name:       the name to be looked up
 
 *-----------------------------------------------------------------
 */         

int lookup_name(hid_t h4toh5id,
        char* name, 
        int size,
        struct name_table *nametab) {

 
    struct name_table *np; /* temporary pointer of the name table that points to 
                    the beginning address of the current bucket.*/
    h4toh5id_t *dt; /* temporary pointer of h4toh5id */

    dt = H4TOH5I_object(h4toh5id);
    
    if(name == NULL) {
        H4toH5error_set(dt,5,"the name to be looked up is NULL",
             __FILE__,__LINE__);
        return -1;
    }

    if(nametab == NULL) {
        H4toH5error_set(dt,5,"the name table is NULL",
             __FILE__,__LINE__);
        return -1;
    }

    /* look through the linked list starting from the current bucket. 
         If the name    is found, return 1, otherwise, return 0
         after inserting the new bucket. */

    for(np = nametab+hash_fun(name,size); np!= NULL;np = np->next) {
        if(np->name == NULL) {
            return 0;
        }
        if(strcmp(name,np->name)==0){
            return 1;
        }
    }
    return 0;
}

/*-------------------------------------------------------------------
 * Function:    lookup_updatename
 *
 * Purpose: 1. look up whether the same name is used for 
                                    different objects 
            2. then  update the name hash table
 *                          
 * Return:  1, if the name is in the name hash table.
            0, if the name is to be added into the name table.
            -1, otherwise.
 *
 * In :                 
        h4toh5id:  h4toh5 identifier
        size:            the hashtable SIZE.
        nametab:     name hash table
        name:            the name to be looked up
 
 *-----------------------------------------------------------------
 */         

int lookup_updatename(hid_t h4toh5id, 
                    const char* name, 
                    int     size,
                    struct name_table *nametab) {

    struct name_table *np;  /* temporary pointer of the name table that points 
                     to the beginning address of the current bucket.*/
    struct name_table *temptr; /* temporary pointer of the added name table.*/
    h4toh5id_t *dt; /*pointer to the h4toh5 id for error handling */

    dt = H4TOH5I_object(h4toh5id);
    
    if(name == NULL) {
         H4toH5error_set(dt,5,"the name to be looked up is NULL",
             __FILE__,__LINE__);
        return -1;
    }

    temptr = malloc(sizeof(struct name_table));
    if(temptr == NULL) {
         H4toH5error_set(dt,1,
        "insufficient memory space can be allocated to the name table",
        __FILE__,__LINE__);
        return -1;
    }

    if(nametab == NULL) {
        free(temptr);
        H4toH5error_set(dt,5,"nametable is NULL",
             __FILE__,__LINE__);
        return -1;
    }

    temptr->name = malloc(strlen(name)+1);
    if(temptr->name == NULL) {
        free(temptr);
        H4toH5error_set(dt,1,"insufficient memory can be allocated to the table name",
             __FILE__,__LINE__);
        return -1;
    }

    /* look through the linked list starting from the current bucket. 
         If the name    is found, return 1, otherwise, return 0
         after inserting the new bucket. */

    for(np = nametab+hash_fun(name,size); np!= NULL;np = np->next) {
        if(np->name == NULL) {
            np->name = malloc(strlen(name)+1);
            if(np->name == NULL) {
                H4toH5error_set(dt,1,"cannot allocate memory for the object name",
                                     __FILE__,__LINE__);
                free(temptr->name);
                free(temptr);
                return -1;
            }
            strcpy(np->name,name);
            free(temptr->name);
            free(temptr);
            return 0;
        }
        if(strcmp(name,np->name)==0){
            free(temptr->name);
            free(temptr);
            return 1;
        }
        if (np->next == NULL) {
            np->next = temptr;
            temptr->next = NULL;
            strcpy(temptr->name,name);
            return 0;
        }
    }
    return -1;
}



/*-------------------------------------------------------------------
 * Function:    init_nametab
 *
 * Purpose: this function will initialize the name hash table.
 *                       

 * Return:  SUCCEED, table is initialzed. FAIL,otherwise.
 *
 * In : h4toh5id:  h4toh5 identifier
        SIZE:       the hashtable SIZE.
        name_hashtab: pointer to the hash table.
 
 *------------------------------------------------------------------
 */ 

int init_nametab(hid_t h4toh5id, 
         int SIZE, 
         struct name_table * name_hashtab) {

    int i;
    h4toh5id_t *dt;
    dt = H4TOH5I_object(h4toh5id);

    if(name_hashtab == NULL) {
        H4toH5error_set(dt,5,"the table is NULL",
             __FILE__,__LINE__);
        return FAIL;
    }
    for (i=0;i < SIZE; i++) {
        (name_hashtab+i%SIZE)->name = NULL;
        (name_hashtab+i%SIZE)->next = NULL;
    }
    return SUCCEED;
}

/*------------------------------------------------------------------
 * Function:    freenametable
 *
 * Purpose:         free the memory of hash table 
 *                          
 * Return:  0
 *
 * In :                 
        SIZE:       the hashtable SIZE.
        nametab: hash table of the name 
 
 *------------------------------------------------------------------
 */ 
int freenametable(int SIZE,struct name_table *nametab) {

    struct name_table *np;
    struct name_table *temptr;
    struct name_table *temptr1;
    int i;
    
    if(nametab == NULL) return 0;
    /* we first free the additional linked items of the hashtable,
         and then free the whole hash table. */
    for (i = 0;i < SIZE; i++) {
        np = nametab+i;
        temptr1 = np->next;
        while(temptr1 != NULL) {
            temptr = temptr1;
            temptr1 = temptr1->next;
            free(temptr->name);
            free(temptr);
        } 
        if(np->name !=NULL) free(np->name);
    }
    free(nametab);
    return 0;
}

/********IV(3) table used object name as the key for dealing with
                 dimensional scale dataset
            The function is:
                1. get_modname2
                2. modlookup_updatename
    (use name as the key to check whether the table
    is looked up or not)
    
**********/

/*-------------------------------------------------------------------
 * Function:    init_modnametab
 *
 * Purpose: this function will initialize the modified name
                                hash table.
 *                       

 * Return:  SUCCEED, table is initialzed. FAIL,otherwise.
 *
 * In : h4toh5id:  h4toh5 identifier
        SIZE:            the hashtable SIZE
        name_hashtab: pointer to the hash table
 
 *----------------------------------------------------------------
 */ 
int init_modnametab(hid_t h4toh5id,
                int SIZE, 
                struct modname_table * name_hashtab) {

    int i; /* temporary index for "for" loop*/
    h4toh5id_t *dt;/* temporary pointer to h4toh5id */

    dt = H4TOH5I_object(h4toh5id);
    if(name_hashtab == NULL) {
        H4toH5error_set(dt,1,"the table is NULL",
             __FILE__,__LINE__);
        return FAIL;
    }
    for (i=0;i < SIZE; i++) {
        (name_hashtab+i%SIZE)->name1 = NULL;
        (name_hashtab+i%SIZE)->next = NULL;
        (name_hashtab+i%SIZE)->name2 = NULL;
    }
    return SUCCEED;
}

/*------------------------------------------------------------------
 * Function:    modlookup_updatename
 *
 * Purpose:     This routine is for modname_table
                1. look up whether the same name is used for 
                                    different objects 
                2. then update the name hash table
 *                          
 * Return:  1, if the name is in the name hash table.
            0, if the name is to be added into the name table.
           -1, otherwise.
 *
 * In : h4toh5id:  h4toh5 identifier
        size:       the hashtable SIZE.
        nametab: name hash table
        name1:   the name to be looked up
        name2:   the name to be attached with name1
 
 *------------------------------------------------------------------
 */         

int modlookup_updatename(hid_t h4toh5id,
             char* name1,
             char* name2, 
             int size,
             struct modname_table *nametab) {

    struct modname_table *np; /* temporary pointer of the name table that points 
                        to the beginning address of the current bucket.*/
    struct modname_table *temptr; /* temporary pointer of the name table*/
                        
    h4toh5id_t *dt; /* temporary pointer of h4toh5id */

    dt = H4TOH5I_object(h4toh5id);

    if(name1 == NULL || name2 == NULL) {
        H4toH5error_set(dt,4,"Inputting names  are NULL in the table",
             __FILE__,__LINE__);
        return -1;
    }

    for(np = nametab+hash_fun(name1,size); np!= NULL;np=np->next) {
        if(np->name1 == NULL) {
            np->name1 = malloc(strlen(name1)+1);
            strcpy(np->name1,name1);
            np->name2 = malloc(strlen(name2)+1);
            strcpy(np->name2,name2);
            return 0;
        }
        if(strcmp(name1,np->name1)==0) 
            return 1;
        if (np->next == NULL) {
            temptr=malloc(sizeof(struct modname_table));
            np->next = temptr;
            temptr->next = NULL;
            temptr->name1=malloc(strlen(name1)+1);
            temptr->name2=malloc(strlen(name2)+1);
            strcpy(temptr->name1,name1);
            strcpy(temptr->name2,name2);
            return 0;
        }
    }
    return -1;
}

/*-------------------------------------------------------------------------
 * Function:    get_modname2
 *
 * Purpose:    obtain the name of the object from modified name hash table
 *                          
 * Return:  the name associated with the key
 *
 * In : h4toh5id:  h4toh5 identifier
        name1:  object name 1 as the key
        SIZE:       the hashtable SIZE
        nametab: pointer to the modified hash table
     
 *-------------------------------------------------------------------
 */             
char* get_modname2(hid_t h4toh5id,
             char*name1,
             int size, 
             struct modname_table *nametab)
{

    struct modname_table *np; /*temporary pointer to the modname_table. */
    char* tempname; /* temporary name */
    h4toh5id_t *dt; /* pointer to h4toh5id for error handling */

    dt = H4TOH5I_object(h4toh5id);

    for(np = nametab+hash_fun(name1,size); np!= NULL;np=np->next) {
        if(np->name1 == NULL) {
            H4toH5error_set(dt,4,"object name(as the key for the table) is NULL",
             __FILE__,__LINE__);
            return NULL;
        }
        if(strcmp(name1,np->name1)==0) {
            if(np->name2 == NULL) {
                H4toH5error_set(dt,4,"the name attached is NULL",
                                __FILE__,__LINE__);
                return NULL;
            }
            tempname = malloc(strlen(np->name2)+1);
            strcpy(tempname,np->name2);
            return tempname;
        }
    }
    return NULL;
}

/*------------------------------------------------------------------
 * Function:    freemodnametable
 *
 * Purpose:         free the memory of modified hash table 
 *                          
 * Return:  0
 *
 * In :                 
        SIZE:       the hashtable SIZE.
        nametab: hash table of the name 
 
 *-------------------------------------------------------------------
*/  

int freemodnametable(int SIZE,struct modname_table *nametab) {

    struct modname_table *np; /* the hashtable pointer */
    struct modname_table *temptr; /* the temporary hashtable pointer to store
                     deleted hash table. */
    struct modname_table *temptr1; /* another temporary hashtable pointer to 
                        store the deleted hash table. */
    int i; /* the temporary index variable for the for loop. */

    if(nametab == NULL) return 0;
    for (i =0;i < SIZE; i++) {
        np = nametab+i;
        temptr1 = np->next;
        while(temptr1!= NULL) {
            temptr = temptr1;
            temptr1 = temptr1->next;
            if(temptr->name1 != NULL)
                free(temptr->name1);
            if(temptr->name2 != NULL)
                free(temptr->name2);
            free(temptr);
        } 
        if(np->name1 !=NULL) free(np->name1);
        if(np->name2 != NULL) free(np->name2);
    }
    free(nametab);
    return 0;
}

/*** PART V MISC. Functions. ****/

/*-------------------------------------------------------------------------
 * Function:    get_obj_aboname
 *
 * Purpose:     get absolute path name of HDF5 object
        In this function, we will deal with name clashing.
        If we find an object name(by using lookup_updatename routine)
        that has already been used,
        we will create a new name for this object. We will follow
        object type(vgroup,sds,image,palette, vdata) plus reference
        number to make it unique.
 *                          
 * Return:  NULL if failed, object name if successful.
 *
 * In : h4toh5id:  h4toh5 identifier
        obj_name: relative object name 
        ref_str: reference number in character format
        path_name: absolute path 
        objstr: object type in character format
                                name_hashtab: the name hash table that is checked
                                tablesize:  the size of the table
                                check_nameptr: pointer to check whether this HDF4 object
                                name is used to create HDF5 object name
 
 *-------------------------------------------------------------------------
 */ 

char* get_obj_aboname(hid_t h4toh5id, 
                    char* obj_name,
                    char* refstr,
                    const char* path_name,
                    const char*objstr,
                    struct name_table*name_hashtab,
                    int tablesize,
                    int* check_nameptr ) {


    char *abo_objname = NULL; /* absolute object name */
    int check_name;     /* a temporary flag to check name*/
    char check_char; /* a temporary flag to check character */
    h4toh5id_t *dt; /* a pointer to h4toh5 id */

    dt = H4TOH5I_object(h4toh5id);

    /* sometimes although the object name is not NULL, but it is empty. 
         We will use make_objname_no in this case. */
    if(obj_name != NULL) check_char = *obj_name;

    /* obtain the absolute name of the object. */
    if (obj_name == NULL || check_char == '\0')
        abo_objname = make_objname_no(h4toh5id,refstr,path_name,objstr);
    else 
        abo_objname = make_objname_yes(h4toh5id,obj_name,path_name);
 
    if(abo_objname == NULL) {
        H4toH5error_set(dt,5,"abosolute path object name is NULL",
             __FILE__,__LINE__);
        return NULL;
    }
    /* look up the name and see whether there is name clashing here.
         if yes, remake the object name.*/
    check_name = lookup_name(h4toh5id,abo_objname,tablesize,name_hashtab);
    *check_nameptr = check_name;
    if(check_name == 1) {
        /* name_clashing is found. We use make_objname_no to build up
             new abo_objname.*/

        if(objstr != NULL && refstr != NULL){
            free(abo_objname);
            abo_objname = make_objname_no(h4toh5id,refstr,path_name,objstr);
        }
    }
 
    return abo_objname;
}

/*------------------------------------------------------------------
 * Function:        free_allhashmemory(h4toh5id_t*)
 *
 * Purpose:         free memory allocated for all hashtables
 *                          
 * Return:          
 *
 * In :                 pointer to the struct of h4toh5id_t
                             
                             
     Out:
     Modification:               
 *-------------------------------------------------------------------
 */ 

int free_allhashmemory(h4toh5id_t*temp_h4toh5){

    int32 num_sds; /* number of SDS objects. */
    int32 num_images; /* number of image objects. */
    int32 num_glsdsattrs; /* number of global SD attributes. */
    int32 num_glgrattrs; /* number of global GR attributes. */

    /* For the netCDF files generated through HDF4 */
    if(temp_h4toh5->file_id == -1) {

        /* obtain number of SDS objects and number of global SD attributes.*/
        if(SDfileinfo(temp_h4toh5->sd_id,&num_sds,&num_glsdsattrs) == FAIL) {
            SDend(temp_h4toh5->sd_id);
            return FAIL;
        }
    
        if(num_sds != 0) {
            freetable(SDS_HASHSIZE,temp_h4toh5->sds_hashtab);
            freemodnametable(DIM_HASHSIZE,temp_h4toh5->moddim_hashtab);
        }
    
        freenametable(OBJECT_HASHSIZE,temp_h4toh5->name_hashtab);
        freenametable(NAME_HASHSIZE,temp_h4toh5->h5groupname_table);
    }
 
    else {
        /* obtain number of SDS objects and number of global SD attributes.*/
        if(SDfileinfo(temp_h4toh5->sd_id,&num_sds,&num_glsdsattrs) == FAIL) {
            SDend(temp_h4toh5->sd_id);
            GRend(temp_h4toh5->gr_id);
            Hclose(temp_h4toh5->file_id);
            return FAIL;
        }
        
        /* obtain number of images and number of global image attributes.*/
        if(GRfileinfo(temp_h4toh5->gr_id,&num_images,&num_glgrattrs) == FAIL) {
            SDend(temp_h4toh5->sd_id);
            GRend(temp_h4toh5->gr_id);
            Hclose(temp_h4toh5->file_id);
            return FAIL;
        }
    
        freetable(VG_HASHSIZE,temp_h4toh5->vg_hashtab);
        freetable(VD_HASHSIZE,temp_h4toh5->vd_hashtab);
    
        if(num_sds != 0) {
            freetable(SDS_HASHSIZE,temp_h4toh5->sds_hashtab);
            freemodnametable(DIM_HASHSIZE,temp_h4toh5->moddim_hashtab);
            freetable2(temp_h4toh5->fakedim_hashtab);
            freenametable(DIMPURE_HASHSIZE,temp_h4toh5->puredim_hashtab);
            freenametable(DIMSCALE_HASHSIZE,temp_h4toh5->dimscale_hashtab);
        
        }
        else {
#ifdef HAVE_LIBHDFEOS
            if(temp_h4toh5->has_swath == 1){
                freemodnametable(DIM_HASHSIZE,temp_h4toh5->moddim_hashtab);
                freetable2(temp_h4toh5->fakedim_hashtab);
                freenametable(DIMPURE_HASHSIZE,temp_h4toh5->puredim_hashtab);
                freenametable(DIMSCALE_HASHSIZE,temp_h4toh5->dimscale_hashtab);
            }
#endif            
        }
    
        if(num_images !=0) {
            freetable(IMAGE_HASHSIZE,temp_h4toh5->gr_hashtab);
            freetable(PAL_HASHSIZE,temp_h4toh5->pal_hashtab);
        }
    
        freenametable(OBJECT_HASHSIZE,temp_h4toh5->name_hashtab);
        freenametable(NAME_HASHSIZE,temp_h4toh5->h5groupname_table);
    }
    return SUCCEED;
}

/*------------------------------------------------------------------
 * Function:        get_h5groupid(char*,hid_t,int)
 *
 * Purpose:         get HDF5 group id
 *                          
 * Return:          HDF5 group id
 *
 * In :             HDF5 group name
                    handler of h4toh5id_t
                    attr option flag(use dim. scale/creation-order or not)
                             
                             
     Out:
     Modification:               
 *-------------------------------------------------------------------
 */
hid_t get_h5groupid(const char* h5groupname,hid_t h4toh5id,int attr_flag) {

    hid_t h5_file; /* HDF5 file id */
    hid_t h5_group = -1; /* HDF5 group id */
    int check_groupname; /* flag to check absolute path of the group */
    h4toh5id_t* temph4toh5_id; /* pointer to h4toh5 id for error handling */

    temph4toh5_id = H4TOH5I_object(h4toh5id);

    h5_file = temph4toh5_id->file5_id;

    /* if the group name cannot be found, create a new group under this name,
         return group_id; Otherwise, return the group id with this name. */

    check_groupname = lookup_updatename(h4toh5id,h5groupname,NAME_HASHSIZE,
                            temph4toh5_id->h5groupname_table);
    if(check_groupname == 1) {
        h5_group = H5GOPEN(h5_file,h5groupname); 
        if(h5_group < 0) {
             H4toH5error_set(temph4toh5_id,3,"failed to open HDF5 group",
             __FILE__,__LINE__);
            return FAIL;    
        }
    }
    else if(check_groupname == 0) {
        if(strcmp(h5groupname,"/")==0)
            h5_group = H5GOPEN(h5_file,h5groupname);
        else 
            h5_group = H4toH5_H5Gcreate(h4toh5id, h5_file,h5groupname,0,attr_flag); 
        if(h5_group < 0) {
            H4toH5error_set(temph4toh5_id,3,"failed to open HDF5 group",
                 __FILE__,__LINE__);
            return FAIL;    
        }
    }
    return h5_group;
}

/*------------------------------------------------------------------
 * Function:        get_h5datasetname
 *
 * Purpose:         get HDF5 dataset name
 *                          
 * Return:          The absolute path of HDF5 dataset name
 *
 * In :              
                    hid_t h4toh5id:      h4toh5 id handler
                    char* h5groupname: absolute path of HDF5 group
                    char*h5dsetname:     relative HDF5 dataset name to 
                                         h5groupname
                    obj_ref:                     object reference number
                    char* HDF4obj:       constant HDF4 object identifier
                                             (HDF4_SDS)
                    int* check_nameptr: integer pointer to check
                                                whether the name is used or not
                             
     Out:
     Modification:               
 *-------------------------------------------------------------------
 */

char* get_h5datasetname(hid_t h4toh5id,
            const char* h5groupname,
            const char* h5dsetname, 
            uint16 obj_ref,
            const char* hdf4obj,
            int tablesize,
            int* check_nameptr) {

    char    refstr[MAXREF_LENGTH]; /* the string format of HDF4 reference number */
    char* cor_h5dsetname = NULL; /* the corrected HDF5 dataset name */
    char* h5cdataset_name = NULL; /* The absolute path of HDF5 dataset name */

    h4toh5id_t* temph4toh5id; /* pointer to h4toh5 id */ 

    temph4toh5id = H4TOH5I_object(h4toh5id);

    /* change format of reference number. */
    if(conv_int_str(h4toh5id,obj_ref,refstr)== FAIL) {
        H4toH5error_set(temph4toh5id,5,"failed to convert reference number into string",
             __FILE__,__LINE__);
        return NULL;
    }
    
    /* obtaining HDF5 dataset name, changing "/" in the dsetname into "_". */
    if(h5dsetname != NULL) {
        cor_h5dsetname = correct_name(h4toh5id,h5dsetname);
        if(cor_h5dsetname == NULL) {
            H4toH5error_set(temph4toh5id,4,"failed to get HDF5 dataset name",
                            __FILE__,__LINE__);
            return NULL;
        }
    }
    if(hdf4obj != NULL) 
        h5cdataset_name= get_obj_aboname(h4toh5id,cor_h5dsetname,refstr,
                         h5groupname,hdf4obj,
                         temph4toh5id->name_hashtab,tablesize,
                         check_nameptr);
    if(h5dsetname != NULL)
        free(cor_h5dsetname);
    return h5cdataset_name;  
}


/*------------------------------------------------------------------
 * Function:        get_orih5datasetname
 *
 * Purpose:         get the original HDF5 dataset name when the object is first
                                looked up and converted.
 *                          
 * Return:          
 *
 * In :             hid_t h4toh5id: h4toh5 id handler
                    char* h5groupname: absolute path of HDF5 group
                    char* h5dsetname: relative HDF5 dataset name to 
                                                                 h5groupname
                    obj_ref: object reference number
                    char* hdf4obj: constant hdf4 object identifier
        (HDF4_SDS)
                    int* check_nameptr: integer pointer to check
        whether the name is used or not
                             
     Out:
     Modification:  
     Note: This routine is not used by the current library. It can be set
                 as a reference for users who want to do something else.
 *-------------------------------------------------------------------
 */

char* get_orih5datasetname(hid_t h4toh5id, 
                 uint16 obj_ref,
                 const char* hdf4obj,
                 int tablesize) {

    char* h5cdataset_name = NULL;
    int check_lookup;
    int check_getname;

    /* define h4toh5 temporary variable. */
    h4toh5id_t* temph4toh5id;  
    check_getname = 0;

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

    /**need to know which table we are looking for. ***/

    if(strncmp(hdf4obj,HDF4_SDS,strlen(HDF4_SDS))==0) {
        check_lookup = lookup(h4toh5id,obj_ref,tablesize,temph4toh5id->sds_hashtab,NULL);
        if(check_lookup == 1) {
            h5cdataset_name = get_name(h4toh5id,obj_ref,tablesize,temph4toh5id->sds_hashtab,&check_getname);
        }
    }
    else if(strncmp(hdf4obj,HDF4_IMAGE,strlen(HDF4_IMAGE))==0){
        check_lookup = lookup(h4toh5id,obj_ref,tablesize,temph4toh5id->gr_hashtab,NULL);
        if(check_lookup == 1) {
            h5cdataset_name = get_name(h4toh5id,obj_ref,tablesize,temph4toh5id->gr_hashtab,&check_getname);
        }
    }
    else if(strncmp(hdf4obj,HDF4_PALETTE,strlen(HDF4_PALETTE))==0){
        check_lookup = lookup(h4toh5id,obj_ref,tablesize,temph4toh5id->pal_hashtab,NULL);
        if(check_lookup == 1) {
            h5cdataset_name = get_name(h4toh5id,obj_ref,tablesize,temph4toh5id->pal_hashtab,&check_getname);
        }
    }
    else if(strncmp(hdf4obj,HDF4_VDATA,strlen(HDF4_VDATA))==0){
        check_lookup = lookup(h4toh5id,obj_ref,tablesize,temph4toh5id->vd_hashtab,NULL);
        if(check_lookup == 1) {
            h5cdataset_name = get_name(h4toh5id,obj_ref,tablesize,temph4toh5id->vd_hashtab,&check_getname);
        }
    }
    else if(strncmp(hdf4obj,HDF4_VGROUP,strlen(HDF4_VGROUP))==0){
        check_lookup = lookup(h4toh5id,obj_ref,tablesize,temph4toh5id->vg_hashtab,NULL);
        if(check_lookup == 1) {
            h5cdataset_name = get_name(h4toh5id,obj_ref,tablesize,temph4toh5id->vg_hashtab,&check_getname);
        }
    }
    else {
        H4toH5error_set(temph4toh5id,5,"h4toh5 library doesn't support such objects",
             __FILE__,__LINE__);
        return NULL;
    }

    if(check_lookup == 0) {
        H4toH5error_set(temph4toh5id,5,"this object has not been looked up",
             __FILE__,__LINE__);
        return NULL;
    }
    return h5cdataset_name;  
}

/*------------------------------------------------------------------
 * Function:        H4toH5get_group_name
 *
 * Purpose:         get the absolute path of the HDF5 group name 
 *                          
 * Return:          
 *
 * In :             hid_t h4toh5id: h4toh5 id handler
                    vgroup_id: HDF4 vgroup id
                    h5par_path: The absolute path of HDF5 parent group
                             
   Out:
   Modification:  
   Note: This routine is not used by the current library. It can be set
                 as a reference for users who want to do something else.
 *-------------------------------------------------------------------
 */

char* H4toH5get_group_name(hid_t h4toh5id,
                int32 vgroup_id,
                char* h5par_path){

/*  char vgroup_name[VGNAMELENMAX*10];*/
    char* vgroup_name;
    char* h5_vgroupname = NULL;
    int  check_vgroupname;
    uint16  vgroupnamelen;

    /* define h4toh5 temporary variable. */
    h4toh5id_t* temph4toh5id;  

    /* obtain global table*/
    temph4toh5id = H4TOH5I_object(h4toh5id);
    
/*  h4toh5_ZeroMemory(vgroup_name,VGNAMELENMAX*10);*/
    if(Vgetnamelen(vgroup_id,&vgroupnamelen) == FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup name length",
                                            __FILE__,__LINE__);
        return NULL;
    }

    vgroup_name = (char*) malloc((vgroupnamelen+1)*sizeof(char));

    if(vgroup_name == NULL) {
        H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                                                __FILE__,__LINE__);
        return NULL;
    }

    check_vgroupname=0;
    if(Vgetname(vgroup_id,vgroup_name)==FAIL){
        H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup name",
             __FILE__,__LINE__);
	free(vgroup_name);
        return NULL;
    }
    
    /* build the absolute path of vgroup */
    if(vgroup_name != NULL) {
        if(h5par_path == NULL) 
            h5_vgroupname = malloc(strlen(vgroup_name)+2);
        else 
            h5_vgroupname = malloc(strlen(h5par_path)+strlen(vgroup_name)+2);
        if(h5_vgroupname == NULL) {
            H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                    __FILE__,__LINE__);
	    free(vgroup_name);
            return NULL;
        }
    }
    if(vgroup_name != NULL){
        if(h5par_path == NULL) {
            strcpy(h5_vgroupname,"/");
            strcat(h5_vgroupname,vgroup_name);
        }
        else if(strcmp(h5par_path,"/")==0) {
            strcpy(h5_vgroupname,h5par_path);
            strcat(h5_vgroupname,vgroup_name);
        } 
        /* else if(strncmp(vgroup_name,"/",1)==0) {
            strcpy(h5_vgroupname,vgroup_name);
        }*/
        else {
           strcpy(h5_vgroupname,h5par_path);
           strcat(h5_vgroupname,"/");
           strcat(h5_vgroupname,vgroup_name);
        }
    
        /*check whether this path is used by other object or not */
        check_vgroupname = H4toH5check_objname_in_use(h4toh5id,NULL,vgroup_name);
        if(check_vgroupname <0){
             H4toH5error_set(temph4toh5id,4,"failed to check object name information",
                 __FILE__,__LINE__);
	     free(vgroup_name);
	     free(h5_vgroupname);
             return NULL;
        }
    }

    /* create a new absolute path if the object name is used. */
    if (check_vgroupname !=0){
        if(h5_vgroupname != NULL) 
	    free(h5_vgroupname);
        h5_vgroupname = H4toH5get_clash_groupname(h4toh5id,vgroup_id,h5par_path);
    }
    free(vgroup_name);

    return h5_vgroupname;
}

/*------------------------------------------------------------------
 * Function:        H4toH5get_clash_groupname
 *
 * Purpose:         get the original HDF5 dataset name when the object is first
                                looked up and converted.
 *                          
 * Return:          
 *
 * In :             hid_t h4toh5id: h4toh5 id handler
                    vgroup_id: HDF4 vgroup id
                    h5par_path: The absolute path of HDF5 parent group
                             
     Out:
     Modification:  
     Note: This routine is not used by the current library. It can be set
                 as a reference for users who want to do something else.
 *-------------------------------------------------------------------
 */
char * H4toH5get_clash_groupname(hid_t h4toh5id,
                 int32 vgroup_id,
                 char*h5par_path){
    int32 vgroup_ref;
    char refstr[MAXREF_LENGTH];
    char * h5par_name;

     /* define h4toh5 temporary variable. */
    h4toh5id_t* temph4toh5id;  

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

    vgroup_ref = VQueryref(vgroup_id);

    if(conv_int_str(h4toh5id,(uint16)vgroup_ref,refstr)== FAIL) {
         H4toH5error_set(temph4toh5id,5,"failed to convert reference number into string",
             __FILE__,__LINE__);
        return NULL;
    }

    h5par_name = make_objname_no(h4toh5id,refstr,h5par_path,HDF4_VGROUP);
    return h5par_name;
}

/*------------------------------------------------------------------
 * Function:        H4toH5get_SDS_name
 *
 * Purpose:         get the absolute path of SDS object
 *                          
 * Return:          
 *
 * In :             hid_t h4toh5id: h4toh5 id handler
                    sds_id: HDF4 SDS id
                    h5par_path: The absolute path of HDF5 parent group
                             
     Out:
     Modification:  
     Note: This routine is not used by the current library. It can be set
                 as a reference for users who want to do something else.
 *-------------------------------------------------------------------
 */

char* H4toH5get_SDS_name(hid_t h4toh5id,
            int32 sds_id,
            char* h5par_path){

    char        sdsname[FIELDNAMELENMAX];
    int32       sds_dtype; /* SDS data type */
    int32       sds_rank; /* rank of SDS */
    int32       sds_dimsizes[H4_MAX_VAR_DIMS]; /* array to describe dimensional 
                     size of SDS */
    int32       num_sdsattrs; /* number of SDS attributes */
    char*       h5_sdsname = NULL;
    int         check_sdsname;

    /* define h4toh5 temporary variable. */
    h4toh5id_t* temph4toh5id;  

    /* obtain global table*/
    temph4toh5id = H4TOH5I_object(h4toh5id);
    sdsname[0] = '\0';
     /*obtain name,rank,dimsizes,datatype and num of attributes of sds */
    if (SDgetinfo(sds_id,sdsname,&sds_rank,sds_dimsizes,&sds_dtype,
        &num_sdsattrs)==FAIL) {
        H4toH5error_set(temph4toh5id,2,
                 "unable to get information of SDS object",
                 __FILE__,__LINE__);
        return NULL;
    }

    check_sdsname = 0;

    /* build the absolute path of HDF4 SDS object */
    if(sdsname[0] != '\0') {
        if(h5par_path == NULL) 
            h5_sdsname = malloc(strlen(sdsname)+2);
        else 
            h5_sdsname = malloc(strlen(h5par_path)+strlen(sdsname)+2);
        if(h5_sdsname == NULL) {
            H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
             __FILE__,__LINE__);
            return NULL;
        }
    }
    if(sdsname[0] != '\0'){
        if(h5par_path == NULL) {
            strcpy(h5_sdsname,"/");
            strcat(h5_sdsname,sdsname);
        }
        else if(strcmp(h5par_path,"/")==0) {
            strcpy(h5_sdsname,h5par_path);
            strcat(h5_sdsname,sdsname);
        } 
        else {
           strcpy(h5_sdsname,h5par_path);
           strcat(h5_sdsname,"/");
           strcat(h5_sdsname,sdsname);
        }
       
           /* check whether the object name is clashed or not */
        check_sdsname = H4toH5check_objname_in_use(h4toh5id,NULL,sdsname);
        if(check_sdsname <0){
            H4toH5error_set(temph4toh5id,4,"failed to check object name information",
                __FILE__,__LINE__);
	    free(h5_sdsname);
           return NULL;
        }
    }

    /* build a new object name is the original SDS name is clashed. */
    if (sdsname[0] =='\0' || check_sdsname !=0){
        if(h5_sdsname != NULL) free(h5_sdsname);
        h5_sdsname = H4toH5get_clash_SDSname(h4toh5id,sds_id,h5par_path);
    }
    return h5_sdsname;
}

/*------------------------------------------------------------------
 * Function:        H4toH5get_clash_SDSname
 *
 * Purpose:         get the original HDF5 dataset name when the object is first
                                looked up and converted.
 *                          
 * Return:          
 *
 * In :             hid_t h4toh5id: h4toh5 id handler
                    sds_id: HDF4 SDS id
                    h5par_path: The absolute path of HDF5 parent group
                             
     Out:
     Modification:  
     Note: This routine is not used by the current library. It can be set
                 as a reference for users who want to do something else.
 *-------------------------------------------------------------------
 */
char * H4toH5get_clash_SDSname(hid_t h4toh5id,
                         int32 sds_id,
                         char* h5par_path){

    int32 sds_ref;
    char refstr[MAXREF_LENGTH];
    char * h5par_name;

    /* define h4toh5 temporary variable. */
    h4toh5id_t* temph4toh5id;  

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

    sds_ref = SDidtoref(sds_id);
    if(sds_ref == FAIL) {
         H4toH5error_set(temph4toh5id,2,"failed to obtain SDS reference number",
             __FILE__,__LINE__);
        return NULL;
    }

    if(conv_int_str(h4toh5id,(uint16)sds_ref,refstr)== FAIL) {
         H4toH5error_set(temph4toh5id,5,"failed to convert reference number into string",
             __FILE__,__LINE__);
        return NULL;
    }

    h5par_name = make_objname_no(h4toh5id,refstr,h5par_path,HDF4_SDS);
    return h5par_name;
}


/*------------------------------------------------------------------
 * Function:        H4toH5get_image_name
 *
 * Purpose:         get the absolute path of image object.
 *                          
 * Return:          
 *
 * In :             hid_t h4toh5id: h4toh5 id handler
                    vgroup_id: HDF4 image id
                    h5par_path: The absolute path of HDF5 parent group
                             
     Out:
     Modification:  
     Note: This routine is not used by the current library. It can be set
                 as a reference for users who want to do something else.
 *-------------------------------------------------------------------
 */

char* H4toH5get_image_name(hid_t h4toh5id,
                int32 image_id,
                char* h5par_path){

    char        imagename[FIELDNAMELENMAX];
    int32       image_dtype; /* IMAGE data type */
    int32       image_dimsizes[2]; /* array to describe dimensional 
                     size of IMAGE */
    int32       num_imageattrs; /* number of IMAGE attributes */
    int32  interlace_mode;
    int32  ncomp;
    char* h5_imagename = NULL;
    int  check_imagename;

    /* define h4toh5 temporary variable. */
    h4toh5id_t* temph4toh5id;  

    /* obtain global table*/
    temph4toh5id = H4TOH5I_object(h4toh5id);
    
    imagename[0]='\0';
    /*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 information of IMAGE object",
                 __FILE__,__LINE__);
        return NULL;
    }

    check_imagename = 0;

    /* build up the absolute path of the image name */
    if(imagename[0] != '\0') {
        if(h5par_path == NULL) 
            h5_imagename = malloc(strlen(imagename)+2);
        else 
            h5_imagename = malloc(strlen(h5par_path)+strlen(imagename)+2);
        if(h5_imagename == NULL) {
            H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                 __FILE__,__LINE__);
            return NULL;
        }
    }
    if(imagename[0] != '\0'){
        if(h5par_path == NULL) {
            strcpy(h5_imagename,"/");
            strcat(h5_imagename,imagename);
        }
        else if(strcmp(h5par_path,"/")==0) {
            strcpy(h5_imagename,h5par_path);
            strcat(h5_imagename,imagename);
        } 
        else {
            strcpy(h5_imagename,h5par_path);
            strcat(h5_imagename,"/");
            strcat(h5_imagename,imagename);
        }
    
        /* check whether the absolute path is used or not */
        check_imagename = H4toH5check_objname_in_use(h4toh5id,NULL,imagename);
        if(check_imagename <0){
            H4toH5error_set(temph4toh5id,4,"failed to check object name information",
             __FILE__,__LINE__);
	    free(h5_imagename);
            return NULL;
        }
    }

    /* create the new absolute path of the image name */
    if (imagename[0] == '\0' || check_imagename !=0){
        if(h5_imagename != NULL) 
	  free(h5_imagename);
        h5_imagename = H4toH5get_clash_imagename(h4toh5id,image_id,h5par_path);
    }
    return h5_imagename;
}

/*------------------------------------------------------------------
 * Function:        H4toH5get_clash_imagename
 *
 * Purpose:         get the original HDF5 dataset name when the object is first
                                looked up and converted.
 *                          
 * Return:          
 *
 * In :             hid_t h4toh5id: h4toh5 id handler
                    image_id: HDF4 IMAGE id
                    h5par_path: The absolute path of HDF5 parent group
                             
     Out:
     Modification:  
     Note: This routine is not used by the current library. It can be set
                 as a reference for users who want to do something else.
 *-------------------------------------------------------------------
 */
char * H4toH5get_clash_imagename(hid_t h4toh5id,int32 image_id,char*h5par_path){

    uint16 image_ref;
    char refstr[MAXREF_LENGTH];
    char * h5par_name;

     /* define h4toh5 temporary variable. */
    h4toh5id_t* temph4toh5id;  

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

    image_ref = GRidtoref(image_id);
    if(image_ref == 0) {
         H4toH5error_set(temph4toh5id,2,"failed to obtain IMAGE reference number",
             __FILE__,__LINE__);
        return NULL;
    }

    if(conv_int_str(h4toh5id,image_ref,refstr)== FAIL) {
         H4toH5error_set(temph4toh5id,5,"failed to convert reference number into string",
             __FILE__,__LINE__);
        return NULL;
    }

    h5par_name = make_objname_no(h4toh5id,refstr,h5par_path,HDF4_IMAGE);
    return h5par_name;
}

/*------------------------------------------------------------------
 * Function:        H4toH5get_vdata_name
 *
 * Purpose:         get the original HDF5 dataset name when the object is first
                                looked up and converted.
 *                          
 * Return:          
 *
 * In :             hid_t h4toh5id: h4toh5 id handler
                    vdata_id: HDF4 vdata id
                    h5par_path: The absolute path of HDF5 parent group
                             
     Out:
     Modification:  
     Note: This routine is not used by the current library. It can be set
                 as a reference for users who want to do something else.
 *-------------------------------------------------------------------
 */

char* H4toH5get_vdata_name(hid_t h4toh5id,
                int32 vdata_id,
                char* h5par_path){

    char vdataname[FIELDNAMELENMAX];
    char* h5_vdataname = NULL;
    int  check_vdataname;

    /* define h4toh5 temporary variable. */
    h4toh5id_t* temph4toh5id;  

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

    vdataname[0]='\0';
    if(VSQueryname(vdata_id,vdataname)==FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot query vdata name",
             __FILE__,__LINE__);
            return NULL;
    }
    check_vdataname = 0;

    /* create the absolute path of HDF5 vdata */
    if(vdataname[0] != '\0') {
        if(h5par_path == NULL) 
            h5_vdataname = malloc(strlen(vdataname)+2);
        else 
            h5_vdataname = malloc(strlen(h5par_path)+strlen(vdataname)+2);
        if(h5_vdataname == NULL) {
            H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
             __FILE__,__LINE__);
            return NULL;
        }
    }
    if(vdataname[0] != '\0'){
        if(h5par_path == NULL) {
            strcpy(h5_vdataname,"/");
            strcat(h5_vdataname,vdataname);
        }
        else if(strcmp(h5par_path,"/")==0) {
            strcpy(h5_vdataname,h5par_path);
            strcat(h5_vdataname,vdataname);
        } 
        else {
           strcpy(h5_vdataname,h5par_path);
           strcat(h5_vdataname,"/");
           strcat(h5_vdataname,vdataname);
        }
    
        /* check whether the object name is clashed */
       check_vdataname = H4toH5check_objname_in_use(h4toh5id,NULL,vdataname);
       if(check_vdataname < 0){
           H4toH5error_set(temph4toh5id,4,"failed to check object name information",
                __FILE__,__LINE__);
	   free(h5_vdataname);
           return NULL;
       }
    }

    /* create the new absolute path of the object */
    if (vdataname[0] == '\0' || check_vdataname !=0){
        if(h5_vdataname != NULL) 
	  free(h5_vdataname);
        h5_vdataname = H4toH5get_clash_vdataname(h4toh5id,vdata_id,h5par_path);
    }
    return h5_vdataname;
}

/*------------------------------------------------------------------
 * Function:        H4toH5get_clash_vdataname
 *
 * Purpose:         get the original HDF5 dataset name when the object is first
                                looked up and converted.
 *                          
 * Return:          
 *
 * In :             hid_t h4toh5id: h4toh5 id handler
                    vdata_id: HDF4 VDATA id
                    h5par_path: The absolute path of HDF5 parent group
                             
     Out:
     Modification:  
     Note: This routine is not used by the current library. It can be set
                 as a reference for users who want to do something else.
 *-------------------------------------------------------------------
 */
char * H4toH5get_clash_vdataname(hid_t h4toh5id,int32 vdata_id,char*h5par_path){

    uint16 vdata_ref;
    char refstr[MAXREF_LENGTH];
    char * h5par_name;

     /* define h4toh5 temporary variable. */
    h4toh5id_t* temph4toh5id;  

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

    vdata_ref = VSQueryref(vdata_id);
    if(vdata_ref == 0) {
         H4toH5error_set(temph4toh5id,2,"failed to obtain VDATA reference number",
             __FILE__,__LINE__);
        return NULL;
    }

    if(conv_int_str(h4toh5id,vdata_ref,refstr)== FAIL) {
         H4toH5error_set(temph4toh5id,5,"failed to convert reference number into string",
             __FILE__,__LINE__);
        return NULL;
    }

    h5par_name = make_objname_no(h4toh5id,refstr,h5par_path,HDF4_VDATA);
    return h5par_name;
}

/*------------------------------------------------------------------
 * Function:        H4toH5get_pal_name
 *
 * Purpose:         get the absolute path of the object converted from palette.
 *                          
 * Return:          
 *
 * In :             hid_t h4toh5id: h4toh5 id handler
                    vdata_id: HDF4 vdata id
                    h5par_path: The absolute path of HDF5 parent group
                             
     Out:
     Modification:  
     Note: This routine is not used by the current library. It can be set
                 as a reference for users who want to do something else.
 *-------------------------------------------------------------------
 */

char* H4toH5get_pal_name(hid_t h4toh5id,
                int32 pal_id,
                char* h5par_path){

    char*       h5_palname = NULL;
    
        h5_palname = H4toH5get_clash_palname(h4toh5id,pal_id,h5par_path);
        return h5_palname;
}

/*------------------------------------------------------------------
 * Function:        H4toH5get_clash_palname
 *
 * Purpose:         create the palette name.
 *                          
 * Return:          
 *
 * In :             hid_t h4toh5id: h4toh5 id handler
                    pal_id: HDF4 PAL id
                    h5par_path: The absolute path of HDF5 parent group
                             
     Out:
     Modification:  
     Note: This routine is not used by the current library. It can be set
                 as a reference for users who want to do something else.
 *-------------------------------------------------------------------
 */
char * H4toH5get_clash_palname(hid_t h4toh5id,int32 pal_id,char*h5par_path){

    uint16 pal_ref;
    char refstr[MAXREF_LENGTH];
    char * h5par_name;

     /* define h4toh5 temporary variable. */
    h4toh5id_t* temph4toh5id;  

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

    pal_ref = GRluttoref(pal_id);
    if(pal_ref == 0) {
         H4toH5error_set(temph4toh5id,2,"failed to obtain PAL reference number",
             __FILE__,__LINE__);
        return NULL;
    }

    if(conv_int_str(h4toh5id,pal_ref,refstr)== FAIL) {
         H4toH5error_set(temph4toh5id,5,"failed to convert reference number into string",
             __FILE__,__LINE__);
        return NULL;
    }

    h5par_name = make_objname_no(h4toh5id,refstr,h5par_path,HDF4_PALETTE);
    return h5par_name;
}
/*** Error handling functions ***/
/** the maximum level of h4toh5 converter utility is four. If the error
        handling level exceeds 4, the extra information will be ignored. **/

/*------------------------------------------------------------------
 * Function:        H4toH5error_set
 *
 * Purpose:         set the error information into the linked-list
 *                          
 * Return:          0 always
 *
 * In :             h4toh5id_t*: pointer to h4toh5 id handler
                    int error_code: error code of the linked-list
                    char* error_str: error string 
                    char* filename: the name of the file where errors occur
                    int line: the line number that the error occurs
                             
     Out:
     Modification:               
 *-------------------------------------------------------------------
 */

int H4toH5error_set(h4toh5id_t *dt,
                 int error_code,
                 const char* error_str,
                 const char* filename,
                 int line) {
    
    struct error_list* new_errorlist; /* pointer to error list */
    struct error_list* templist;/* temporary pointer to error list */

    /*allocate the current level error list. */
    new_errorlist = malloc(sizeof(struct error_list));
    if(error_str != NULL){ 
        new_errorlist->errorstr= malloc(strlen(error_str)+1);
        strcpy(new_errorlist->errorstr,error_str);
    } 

    new_errorlist->filename = malloc(strlen(filename)+1);
    strcpy(new_errorlist->filename,filename);
    new_errorlist->linenum = line;
    new_errorlist->errorcode = error_code;
    /*allocate the previous level error list;
        prepended the new_error list ahead of the previous error list*/
    if(dt==NULL) { 
        free(new_errorlist);
        return -1;
    }
    if(dt->h4toh5error == NULL) {
        new_errorlist->next = NULL;
        dt->h4toh5error = new_errorlist;
    }
    else {
        templist = dt->h4toh5error;
        new_errorlist->next = templist;
        dt->h4toh5error = new_errorlist;
    }

    return 0;  
}

int H4toH5error_reset(hid_t h4toh5id)
{
    h4toh5id_t *dt;
    struct error_list *p;
    struct error_list *q;

    dt = H4TOH5I_object(h4toh5id);
    if (dt == NULL) return -1;

    for (p = dt->h4toh5error; p; p = q) {
        q = p->next;
        free(p->errorstr);
        free(p->filename);
        free(p);
    }
    dt->h4toh5error = NULL;
    return 0;
}

static void call_debugger()
{
#ifdef _WIN32
#ifdef _MSC_VER
/*  DebugBreak(); */
#endif
#endif
}

int H4toH5error_suppress(hid_t h4toh5id, int suppress)
{
    h4toh5id_t *dt;

    dt = H4TOH5I_object(h4toh5id);
    if (dt != NULL) {
        dt->error_suppressed = suppress;
    }
    return SUCCEED;
}

int H4toH5error_set0(hid_t h4toh5id, int errorcode, const char *filename, int linenum)
{
    return H4toH5error_set3(h4toh5id, errorcode, NULL, NULL, NULL, filename, linenum);
}

int H4toH5error_set1(hid_t h4toh5id, int errorcode, const char *e1, const char *filename, int linenum)
{
    return H4toH5error_set3(h4toh5id, errorcode, e1, NULL, NULL, filename, linenum);
}

int H4toH5error_set2(hid_t h4toh5id, int errorcode, const char *e1, const char *e2, const char *filename, int linenum)
{
    return H4toH5error_set3(h4toh5id, errorcode, e1, e2, NULL, filename, linenum);
}

int H4toH5error_set3(hid_t h4toh5id, int errorcode, const char *e1, const char *e2, const char *e3, const char *filename, int linenum)
{
    return H4toH5error_set5(h4toh5id, errorcode, e1, e2, e3, NULL, NULL, filename, linenum);
}

int H4toH5error_set4(hid_t h4toh5id, int errorcode, const char *e1, const char *e2, const char *e3, const char *e4, const char *filename, int linenum)
{
    return H4toH5error_set5(h4toh5id, errorcode, e1, e2, e3, e4, NULL, filename, linenum);
}

int H4toH5error_set5(hid_t h4toh5id, int errorcode, const char *e1, const char *e2, const char *e3, const char *e4, const char *e5, const char *filename, int linenum)
{
    char *str;
    unsigned int length = 0;
    int ret = -1;
    h4toh5id_t *dt;

    dt = H4TOH5I_object(h4toh5id);
    if (dt != NULL) {
        length += e1 ? strlen(e1) : 0;
        length += e2 ? strlen(e2) + 1 : 0;
        length += e3 ? strlen(e3) + 1 : 0;
        length += e4 ? strlen(e4) + 1 : 0;
        length += e5 ? strlen(e5) + 1 : 0;

        str = malloc(length + 1);
        if (str != NULL) {
            strcpy(str, "");
            if (e1) strcat(str, e1);
            if (e2) { strcat(str, " "); strcat(str, e2); }
            if (e3) { strcat(str, " "); strcat(str, e3); }
            if (e4) { strcat(str, " "); strcat(str, e4); }
            if (e5) { strcat(str, " "); strcat(str, e5); }
            ret = H4toH5error_set(dt, errorcode, str, filename, linenum);
            free(str);
        }
        else {
            ret = H4toH5error_set(dt, errorcode, e1, filename, linenum);
        }
    }
    call_debugger();
    return ret;
}

int H4toH5error_nomem1(hid_t h4toh5id, const char *errorstr1, const char *filename, int linenum)
{
    return H4toH5error_set2(h4toh5id, 3, errorstr1, "memory exhausted", filename, linenum);
}

int H4toH5assert_failure(const char *filename, int linenum)
{
    fprintf(stderr, "assertion failure at %s %d\n", filename, linenum);
    call_debugger();
    exit(1);
}


/*------------------------------------------------------------------
 * Function:        H4toH5error_get
 *
 * Purpose:         get the original HDF5 error information
 *                          
 * Return:          0 always
 *
 * In :              hid_t h4toh5id: h4toh5 id handler
                             
                             
     Out:
     Modification:               
 *-------------------------------------------------------------------
 */
int H4toH5error_get(hid_t h4toh5id) {

    struct error_list* templist; /* pointer to temporary error list */
    char* error_codestr; /* string to store current error category */
    int level; /* number of level */
    h4toh5id_t* dt; /* temporary pointer to h4toh5 id */

    /* obtain global table*/
    dt = H4TOH5I_object(h4toh5id);
    templist = dt->h4toh5error;
    level = 0;
    while(templist != NULL){
        error_codestr = get_codestr(templist->errorcode);
        if (!dt->error_suppressed) {
            fprintf(stderr,"\n");
            fprintf(stderr,"LEVEL ");
            fprintf(stderr,"%d\n",level);
            fprintf(stderr,"%s",error_codestr);
            fprintf(stderr,": ");
            fprintf(stderr,"%s",templist->errorstr);
            fprintf(stderr,"\n");
            fprintf(stderr,"at file %s",templist->filename);
            fprintf(stderr," ");
            fprintf(stderr,"%d",templist->linenum);
            fprintf(stderr,"\n");
        }
        else if (templist->next == NULL) {
            /* if error message is suppressed, the deepest error message should be printed */
            fprintf(stderr, "%s\n", templist->errorstr);
        }
        templist = templist->next;
        level++;
        free(error_codestr);
    }
    return 0;
}


char* get_codestr(int errorcode) {

    char* tempstr; /*temporary string to store error information */
    tempstr = malloc(ERR_LEN+1);
    
    switch(errorcode) {

    case 1:
        strcpy(tempstr,"memory allocation failed");
        break;
    case 2:
        strcpy(tempstr,"HDF4 internal errors");
        break;
    case 3:
        strcpy(tempstr,"HDF5 internal errors");
        break;
    case 4:
        strcpy(tempstr,"object name handling errors");
        break;
    case 5:
        strcpy(tempstr,"Other errors");
        break;
    default:
	break;

    }

    return tempstr;
}

        
/*----------------------------------------------------------------
 * Function:    freeerror_list
 *
 * Purpose:         free the memory of error list 
 *                          
 * Return:  0
 *
 * In :                 
        SIZE:       the hashtable SIZE.
        error_list: list 
 
 *------------------------------------------------------------------
 */ 
int freeerror_list(struct error_list *list) {

    struct error_list *templist; /* temporary pointer to error list */

    /* Free error list */
    while(list != NULL) {
        templist = list;
        free(list->errorstr);
        free(list->filename);
        list = list->next;
        free(templist);
    }
    return 0;
}


void init_h4toh5id_t(h4toh5id_t *dt)
{
    dt->sds_hashtab = NULL;
    dt->gr_hashtab = NULL;
    dt->vg_hashtab = NULL;
    dt->vd_hashtab = NULL;
    dt->pal_hashtab = NULL;
    dt->name_hashtab = NULL;
    /*dt->dim_hashtab = NULL;*/
    dt->moddim_hashtab = NULL;
    dt->h5groupname_table = NULL;

    dt->file_id = -1;
    dt->gr_id = -1;
    dt->sd_id = -1;
#ifdef HAVE_LIBHDFEOS
    dt->hdf4filename = NULL;
    dt->gd_fd = -1;
    dt->sw_fd = -1;
    dt->pt_fd = -1;
    dt->grid_list = NULL;
    dt->swath_list = NULL;
    dt->point_list = NULL;
    dt->created_datasets = NULL;
    dt->manglednames = NULL;
    dt->eos2data = NULL;
#endif
    dt->file5_id = -1;
    dt->h4toh5error = NULL;
    dt->error_suppressed = 0;
}

hid_t H4toH5_H5Gcreate(hid_t h4toh5id, hid_t loc_id, const char *name, size_t size_hint,int attr_flag)
{

    int use_creation_order = 0;
#ifdef HAVE_LIBHDFEOS
    if(H4toH5config_use_netcdf4_hack())
        use_creation_order = 1;
#else
    if(attr_flag == H425_ALLATTRS || attr_flag == H425_NO_PREDEF_ATTRS || attr_flag == H425_SV)
        use_creation_order = 1;
#endif

    if (1 == use_creation_order) {
        hid_t gcpl_id = FAIL;
        hid_t grpid = FAIL;
        int succeeded = 0;

        do {
            if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { H4TOH5ERROR_SET1(3, "H5Pcreate failure"); break; }
            if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) { H4TOH5ERROR_SET1(3, "H5Pset_link_creation_order"); break; }
            if (H5Pset_attr_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) { H4TOH5ERROR_SET1(3, "H5Pset_attr_creation_order"); break; }

            if ((grpid = H5Gcreate_anon(loc_id, gcpl_id, H5P_DEFAULT)) < 0) { H4TOH5ERROR_SET1(3, "H5Gcreate_anon"); break; }
/*          if ((H5Llink(loc_id, name, grpid, H5P_DEFAULT, H5P_DEFAULT)) < 0) { H4TOH5ERROR_SET1(3, "H5Link"); break; } */
            if ((H5Olink(grpid, loc_id, name, H5P_DEFAULT, H5P_DEFAULT)) < 0) { H4TOH5ERROR_SET1(3, "H5Link"); break; }

            succeeded = 1;
        } while (0);

        if (1) {
            if (gcpl_id != FAIL) H5Pclose(gcpl_id);
        }
        if (!succeeded) {
            if (grpid != FAIL) H5Gclose(grpid);
        }
        return succeeded ? grpid : FAIL;
    }
    else {
        return H5GCREATE(loc_id, name, size_hint);
    }
}

/* Return 1 if the flag is valid, return 0 if the flag is not valid. */
int is_valid_attr_flag(int attr_flag) {

        if(attr_flag == H425_NOATTRS || attr_flag == H425_OSPEC_ALLATTRS || attr_flag == H425_ALLATTRS || attr_flag == H425_NO_PREDEF_ATTRS 
             || attr_flag == H425_OSPEC_NO_PREDEF_ATTRS || attr_flag == H425_SV)
             return 1;
        else 
             return 0;

}
hid_t H5Acreate_safe(hid_t h4toh5id, hid_t loc_id, const char *name, hid_t type_id, hid_t space_id, hid_t acpl_id)
{
    char *corrected = NULL;
    const char *safename = name;
    hid_t aid = -1;

#ifdef HAVE_LIBHDFEOS
    /* attribute name matters only if netCDF-4 matters */
    if (H4toH5config_use_netcdf4_hack()) {
        if ((corrected = H4toH5correct_name_netcdf4(h4toh5id, name)) == NULL) {
            H4TOH5ERROR_NOMEM1("escape name");
            return aid;
        }
        safename = corrected;
    }
#endif

    /* The second chance is allowed. */
    H5E_BEGIN_TRY {
        aid = H5ACREATE(loc_id, safename, type_id, space_id, acpl_id);
    } H5E_END_TRY;

    free(corrected);
    return aid;
}

typedef struct {
    int recognize_eos2;
    int netcdf4_hack;
    int netcdf4_strict;
    int netcdf4_fakedim;
    int verbose_msg;
    int latest_format;
} convert_config_t;

static convert_config_t convert_config;

/** 
* @brief set flags used when converting HDF4 to HDF5 file.
* 
* @param eos2 if set, it recognizes EOS2-specific dimension scale
* @param nc4hack if set, it generates an HDF5 file that can be read by netCDF4
*/
int H4toH5set_convert_flags(int eos2, int nc4hack, int nc4strict, int nc4fakedim, int verbose, int hdf5latest)
{
    /* Possible combinations
     *   nc4strict implies nc4hack
     *   nc4fakedim implies nc4hack
     *   nc4strict || nc4fakedim is possible
     * The caller should guarantee the combinations by recognizing user's options.
     */
    if (!nc4hack && nc4strict) {
        fprintf(stderr, "impossible combination (nc4strict does not imply nc4)\n");
        return FAIL;
    }
    if (!nc4hack && nc4fakedim) {
        fprintf(stderr, "impossible combination (nc4strict does not imply nc4fakedim)\n");
        return FAIL;
    }

    convert_config.recognize_eos2 = eos2;
    convert_config.netcdf4_hack = nc4hack;
    convert_config.netcdf4_strict = nc4strict;
    convert_config.netcdf4_fakedim = nc4fakedim;
    convert_config.verbose_msg = verbose;
    convert_config.latest_format = hdf5latest;
    return SUCCEED;
}

/** 
 * @brief returns the flag saying that this should recognize EOS2-specific dimension scale
 * @see H4toH5set_convert_flags
 * 
 * @return the flag
 */
int H4toH5config_use_eos2_conversion()
{
    return convert_config.recognize_eos2;
}

/** 
 * @brief returns the flag saying that this should generate an HDF5 file that can be read by netCDF4
 * @see set_convert_flags
 * 
 * @return the flag
 */
int H4toH5config_use_netcdf4_hack()
{
    return convert_config.netcdf4_hack;
}

/** 
 * @brief returns the flag saying that this should reject an HDF-EOS2 file when the conversion
 * may generate an HDF5 file that cannot be read by netCDF4
 * @see set_convert_flags
 * 
 * @return the flag
 */
int H4toH5config_use_netcdf4_strict()
{
    return convert_config.netcdf4_strict;
}

/** 
 * @brief returns the flag saying that this converter should create fake dimensions
 * for data fields that don't have associated dimensions.
 * @see set_convert_flags
 * 
 * @return the flag
 */
int H4toH5config_use_netcdf4_fakedim()
{
    return convert_config.netcdf4_fakedim;
}

int H4toH5config_use_verbose_msg()
{
    return convert_config.verbose_msg;
}

int H4toH5config_use_debug_msg()
{
    return convert_config.verbose_msg > 9;
}

int H4toH5config_use_latest_format()
{
    return convert_config.latest_format;
}

#if 0
#ifdef USE_DIMSCALE_APIS
hid_t create_pure_fake_dim_scale(hid_t h4toh5id, 
                                                                 char*cor_sdsdimname,
                                                                 int sds_dimscalesize, 
                                                                 int unlimited_dim){

    h4toh5id_t* dt; /* a pointer to h4toh5 id*/
    hid_t h5_fileid; /* a temporary HDF5 file ID */
    hid_t h5_dsetid; /* HDF5 dataset ID */
    char* h5dim_abo_path; /* absolute path of HDF5 dim. scale */
    hsize_t h5dimscas[1]; /* the size of the HDF5 "dimensional scale" */
    hsize_t max_h5dimscas[1]; /* the maximum size of the HDF5 "dimensional scale" */
    char slash_char[]={'/'};


    hid_t h5dim_sid;
    dt = H4TOH5I_object(h4toh5id);
    h5_fileid = dt->file_id;
    
    h5dimscas[0] = sds_dimscalesize;
    if(unlimited_dim == 1)
        max_h5dimscas[0] = H5S_UNLIMITED;
    else
        max_h5dimscas[0] = h5dimscas[0];
    h5dim_abo_path = malloc(strlen(cor_sdsdimname)+2);
    strncpy(h5dim_abo_path,slash_char,1);
    strncat(h5dim_abo_path,cor_sdsdimname,strlen(cor_sdsdimname));
    
    h5_dsetid = H5DCREATE(h5_fileid,h5dim_abo_path,H5T_NATIVE_INT,h5dim_sid,H5P_DEFAULT);
    H5Dclose(h5_dsetid);
    free(h5dim_abo_path);

}
hid_t create_pure_dim_scale(hid_t h4toh5id, int sdsdim_id, int unlimited_dim){

    h4toh5id_t* dt; /* a pointer to h4toh5 id*/
    hid_t h5_fileid; /* a temporary HDF5 file ID */
    char* h5dim_abo_path; /* absolute path of HDF5 dim. scale */
    dt = H4TOH5I_object(h4toh5id);
    h5_fileid = dt->file_id;
 
}
hid_t create_dim_scale(hid_t h4toh5id, int sdsdim_id, int unlimited_dim){

    h4toh5id_t* dt; /* a pointer to h4toh5 id*/
    hid_t h5_fileid; /* a temporary HDF5 file ID */
    char* h5dim_abo_path; /* absolute path of HDF5 dim. scale */
    dt = H4TOH5I_object(h4toh5id);
    h5_fileid = dt->file_id;
 
}
#endif
#endif


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