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

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

nine C files:

     h4toh5util.c(utility and internal functions)
     h4toh5main.c(H4toH5open and H4toH5close functions)
     h4toh5sds.c(H4toH5sds,h4toh5alldimscale and h4toh5onedimscale functions)
     h4toh5image.c(H4toH5image function)
     h4toh5vdata.c(H4toH5vdata function)
     h4toh5vgroup.c(H4toH5bas_vgroup and H4toH5adv_group functions)
     h4toh5pal.c(h4toh5pal functions)
     h4toh5anno.c(h4toh5anno functions)


2. this file 

converting an HDF4 vgroup into a hdf5 group: 
two APIs: 

1) H4toH5bas_vgroup: convert a vgroup and the non-vgroup member into
an HDF5 group.

2) H4toH5adv_group: convert everything under the current vgroup into 
an HDF5 group.
Author:  Kent Yang(myang6@hdfgroup.org)
 

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


#include "h4toh5main.h"

 
/*-------------------------------------------------------------------------
 * Function:    H4toH5bas_vgroup
 *
 * Purpose:     converts a vgroup to an HDF5 group, depending on the setting
                of the vg_flag parameter, it can either convert this Vgroup 
                only or convert this Vgroup and the non-Vgroup members to
                HDF5 corresponding objects.
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id: h4toh5 identifier
        vgroup_id: hdf4 vgroup id
        h5pargroupname: hdf5 parent group name
        h5chigroupname: hdf5 children group name
        vg_flag: flag to indicate whether only this vgroup
                 or non-vgroup members should be converted 
        attr_flag: flag to indicate whether attributes should
                   be converted or not
  Out:

  Modification:
 *-------------------------------------------------------------------------
 */ 

int H4toH5bas_vgroup(hid_t h4toh5_id,
                int32 vgroup_id,
                char* h5pargroupname,
                char* h5chi_groupname,
                int     vg_flag,
                int     attr_flag) 

{

    int32       vgroup_tag; /* Vgroup tag */
    int32       vgroup_ref; /* Vgroup reference number */
    char*        vgroup_class; /* Vgroup class name */
    char*        vgroup_name; /* Vgroup name */
    uint16  vclassnamelen; /*Vgroup class name length */
    uint16  vgroupnamelen; /*Vgroup name length */

    char*       h5c_groupname; /* The absolute path of HDF5 group name */
    char*       ori_h5cgroup_name; /* The original path of HDF5 group name */
    int         check_tabst;/* the variable to check the table status */
    hid_t       h5_pgroup; /* The absolute path of HDF5 parent group */
    hid_t       h5_cgroup; /* The absolute path of HDF5 children group */
    int         check_groupname; /* The variable to check whether the group name is 
                        used    */
    int         check_vgroup; /* A variable to check whether the group is used */
    int*        check_lookupptr; /* A pointer to pass the flag about the group status */
    int         temp;
    int         temp_flag;
    herr_t  ret;    /* the flag to check the "return" status of HDF5 APIs. */

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

    check_groupname = 0;
    temp                        = 0;
    check_lookupptr = &temp;

    /* obtain h4toh5 id handler*/
    temph4toh5id = H4TOH5I_object(h4toh5_id);

    if(Vgetnamelen(vgroup_id,&vgroupnamelen) == FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup name length",
                                     __FILE__,__LINE__);
        return FAIL;
    }

    vgroup_name = (char*) malloc((int)(vgroupnamelen+1)*sizeof(char));
    if(vgroup_name == NULL) {
        H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                                         __FILE__,__LINE__);
        return FAIL;
    }

    if(Vgetclassnamelen(vgroup_id,&vclassnamelen) == FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup name length",
                                         __FILE__,__LINE__);
        free(vgroup_name);
        return FAIL;
    }

    vgroup_class = (char*) malloc((int)(vclassnamelen+1)*sizeof(char));
    if(vgroup_class == NULL) {
        H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                                          __FILE__,__LINE__);
        free(vgroup_name);
        return FAIL;
    }

    /* get vgroup tag,reference,name and class name*/
    vgroup_tag = VQuerytag(vgroup_id);
    if(vgroup_tag == FAIL) {
        free(vgroup_name);
        free(vgroup_class);
        H4toH5error_set(temph4toh5id,2,
                 "unable to obtain Vgroup tag",
                  __FILE__,__LINE__);
        return FAIL;
    }

    vgroup_ref = VQueryref(vgroup_id);
    if(vgroup_ref == FAIL) {
        free(vgroup_name);
        free(vgroup_class);
        H4toH5error_set(temph4toh5id,2,
                 "unable to obtain Vgroup reference",
                  __FILE__,__LINE__);
        return FAIL;
    }

    if(Vgetname(vgroup_id,vgroup_name) == FAIL) {
        free(vgroup_name);
        free(vgroup_class);
        H4toH5error_set(temph4toh5id,2,
                 "unable to obtain Vgroup name",
                 __FILE__,__LINE__);
        return FAIL;
    }

    if(Vgetclass(vgroup_id,vgroup_class) == FAIL) {
        free(vgroup_name);
        free(vgroup_class);
        H4toH5error_set(temph4toh5id,2,
                 "unable to obtain Vgroup class name",
                 __FILE__,__LINE__);
        return FAIL;
    }

    /*** ignore reserved HDF groups ***/
    if(vgroup_class != NULL) {
        if(strcmp(vgroup_class,_HDF_ATTRIBUTE) == 0) {
            free(vgroup_name);
            free(vgroup_class);
            return SUCCEED;
        }
        if(strcmp(vgroup_class,_HDF_VARIABLE)  == 0) { 
            free(vgroup_name);
            free(vgroup_class);
            return SUCCEED;
        }
        if(strcmp(vgroup_class,_HDF_DIMENSION) == 0) {
            free(vgroup_name);
            free(vgroup_class);
            return SUCCEED;
        }
        if(strcmp(vgroup_class,_HDF_UDIMENSION)== 0) {
            free(vgroup_name);
            free(vgroup_class);
            return SUCCEED;
        }
        if(strcmp(vgroup_class,_HDF_CDF) == 0) { 
            free(vgroup_name);
            free(vgroup_class);
            return SUCCEED;
        }
        if(strcmp(vgroup_class,GR_NAME) == 0) { 
            free(vgroup_name);
            free(vgroup_class);
            return SUCCEED;
        }
        if(strcmp(vgroup_class,RI_NAME) == 0) { 
            free(vgroup_name);
            free(vgroup_class);
            return SUCCEED;
        }
    }
     
    free(vgroup_class);
    if(vgroup_name != NULL) {
        if(strcmp(vgroup_name,GR_NAME) == 0) {
            free(vgroup_name);
            return SUCCEED;
        }

    }

    /* obtain the parent group id and the current absolute path 
         of the group name.*/       
    h5_pgroup = get_h5groupid(h5pargroupname,h4toh5_id,attr_flag);
    if(h5_pgroup <0) {
        H4toH5error_set(temph4toh5id,5,
                 "unable to obtain HDF5 group id",
                 __FILE__,__LINE__);
        free(vgroup_name);
        return FAIL;
    }

    temp_flag = vg_flag;

    /*
        checking whether this group had been looked up. 
    */

    check_vgroup = lookup(h4toh5_id,vgroup_ref,VG_HASHSIZE,
            temph4toh5id->vg_hashtab,&temp_flag);

    /* obtaining the absolute path of the converted group */
    if(h5chi_groupname == NULL) {

        /* 
             1) Assume the user will not use HDF4_VG_REF as their own 
                    group name. 
             2) Check whether this vgroup was looked up or not. If this vgroup 
                    has been looked up, it must be assigned a name. 
        lookup_name is used to make sure the obtained name is not used 
        before. 
        */

        h5c_groupname= get_h5datasetname(h4toh5_id,h5pargroupname,vgroup_name,
                         (uint16)vgroup_ref,HDF4_VGROUP,OBJECT_HASHSIZE,check_lookupptr);

        free(vgroup_name);
        if(h5c_groupname == NULL) {
            H4toH5error_set(temph4toh5id,4,
            "unable to obtain the absolute path of HDF5 child group",
            __FILE__,__LINE__);
            H5Gclose(h5_pgroup);
            return FAIL;
        }
        
        if(lookup_name(h4toh5_id,h5c_groupname,OBJECT_HASHSIZE,
             temph4toh5id->name_hashtab)== 1) {
             H4toH5error_set(temph4toh5id,4,
             "this group name has been used already",
             __FILE__,__LINE__);
            H5Gclose(h5_pgroup);
            free(h5c_groupname);
            return FAIL;
        }
    }
    else {
        free(vgroup_name);
        h5c_groupname = get_h5datasetname(h4toh5_id,h5pargroupname,h5chi_groupname,
                            (uint16)vgroup_ref,HDF4_VGROUP,OBJECT_HASHSIZE,&check_groupname);
        if(check_groupname == 1) {
                H4toH5error_set(temph4toh5id,4,
             "this group name has been used already",
             __FILE__,__LINE__);
             free(h5c_groupname);
             H5Gclose(h5_pgroup);
             return FAIL;
        }
    }
    

    /*update the HDF5 group name in both object name hash table 
        and group name hash table.*/
    if(lookup_updatename(h4toh5_id,h5c_groupname,OBJECT_HASHSIZE,
                     temph4toh5id->name_hashtab)==-1) {
        H4toH5error_set(temph4toh5id,4,
         "cannot update the name in the name_hashtable",
         __FILE__,__LINE__);
        H5Gclose(h5_pgroup);
        free(h5c_groupname);
        return FAIL;
    }

    if(lookup_updatename(h4toh5_id,h5c_groupname,NAME_HASHSIZE,
                     temph4toh5id->h5groupname_table)==-1) {
        H4toH5error_set(temph4toh5id,4,
           "cannot update the name in the groupname_table",
           __FILE__,__LINE__);
        H5Gclose(h5_pgroup);
        free(h5c_groupname);
        return FAIL;
    }


    /* if this vgroup had been looked up,
        
        1) build up a hard link.
        2) if the original option(temp_flag) is converting vgroup only,  
             and the current vg_flag is ;
             convert all members of this original vgroup into HDF5 objects.     
             For other combinations, no conversion is made.
    */

    if(check_vgroup == 1) {
     
        ori_h5cgroup_name = get_name(h4toh5_id,vgroup_ref,VG_HASHSIZE,
                 temph4toh5id->vg_hashtab,&check_groupname);
        
        if(vg_flag == H425_ALLMEMBERS && temp_flag == H425_NOMEMBERS) { 
            /* converting all the objects except vgroup to hdf5 datasets. */
            if(convert_vgroupobjects(h4toh5_id,ori_h5cgroup_name,vgroup_id,0,
                         attr_flag)==FAIL) {
                H4toH5error_set(temph4toh5id,5,
                         "cannot convert Vgroup objects successfully",
                         __FILE__,__LINE__);
                H5Gclose(h5_pgroup);
                free(h5c_groupname);
                free(ori_h5cgroup_name);
                return FAIL;
            }
        }

        if(H5Glink(h5_pgroup,H5G_LINK_HARD,ori_h5cgroup_name,h5c_groupname) <0) {
            H4toH5error_set(temph4toh5id,3,
             "cannot create Hard link between groups",
             __FILE__,__LINE__);
            free(h5c_groupname);
            free(ori_h5cgroup_name);
            H5Gclose(h5_pgroup);
            return FAIL;
        }
        free(h5c_groupname);
        free(ori_h5cgroup_name);
        if(H5Gclose(h5_pgroup)<0) {
            H4toH5error_set(temph4toh5id,3,
             "cannot close HDF5 group",
             __FILE__,__LINE__);
            return FAIL;
        }
        return SUCCEED;
    }
        
    else {
     if(check_vgroup == 0) { 
            
        check_tabst = set_name(h4toh5_id,vgroup_ref,VG_HASHSIZE,
                 temph4toh5id->vg_hashtab,h5c_groupname,vg_flag);

        if(check_tabst == FAIL) {
            H4toH5error_set(temph4toh5id,1,
             "Don't have enough memory to allocate for vgroup name",
             __FILE__,__LINE__);
            free(h5c_groupname);
            H5Gclose(h5_pgroup);
            return FAIL;
        }
     }
    }
        
    h5_cgroup = H4toH5_H5Gcreate(h4toh5_id,h5_pgroup,h5c_groupname,0,attr_flag);

    if(h5_cgroup < 0) {
        H4toH5error_set(temph4toh5id,3,
             "cannot create HDF5 group",
             __FILE__,__LINE__);
        H5Gclose(h5_pgroup);
        free(h5c_groupname);
        return FAIL;
    }

    if(is_valid_attr_flag(attr_flag)==0) {
            H4toH5error_set(temph4toh5id,5,
             "the attribute flag is set wrong",
             __FILE__,__LINE__);
            H5Gclose(h5_cgroup);
            H5Gclose(h5_pgroup);
            free(h5c_groupname);
            return FAIL;    
    }
    
    /* vgroup attributes into corresponding hdf5 group attributes.*/
    if(is_valid_attr_flag(attr_flag) && attr_flag != H425_NOATTRS) {
        if(vg_transattrs(h4toh5_id,vgroup_id,h5_cgroup,attr_flag)==FAIL) {
            H4toH5error_set(temph4toh5id,5,
         "cannot convert vgroup attributes into HDF5 group attributes",
             __FILE__,__LINE__);
            H5Gclose(h5_cgroup);
            H5Gclose(h5_pgroup);
            free(h5c_groupname);
            return FAIL;
        }

        if(H4toH5anno_obj_all_labels_new(h4toh5_id,h5pargroupname,h5c_groupname,
                        (uint16)vgroup_ref,vgroup_tag,attr_flag)==FAIL) {
            H4toH5error_set(temph4toh5id,5,
             "cannot obtain label annotation of the vgroup",
             __FILE__,__LINE__);
            H5Gclose(h5_cgroup);
            H5Gclose(h5_pgroup);
            free(h5c_groupname);
            return FAIL;
        }

        if(H4toH5anno_obj_all_descs_new(h4toh5_id,h5pargroupname,h5c_groupname,
                        (uint16)vgroup_ref,vgroup_tag,attr_flag)==FAIL) {
            H4toH5error_set(temph4toh5id,5,
             "cannot obtain desc annotation of the vgroup",
             __FILE__,__LINE__);
            H5Gclose(h5_cgroup);
            H5Gclose(h5_pgroup);
            free(h5c_groupname);
            return FAIL;
        }
    }

    if(vg_flag == H425_ALLMEMBERS) {

        /* for this routine, vgroup members of this vgroup  will not be 
             converted. */
        if(convert_vgroupobjects(h4toh5_id,h5c_groupname,vgroup_id,
                     0,attr_flag)==FAIL) {
            H4toH5error_set(temph4toh5id,5,
             "cannot convert vgroup objects",
             __FILE__,__LINE__);
            H5Gclose(h5_cgroup);
            H5Gclose(h5_pgroup);
            free(h5c_groupname);
            return FAIL;
        }
    }
    ret = H5Gclose(h5_cgroup);
    if(ret < 0) {
        H4toH5error_set(temph4toh5id,3,
             "cannot close child group interface",
             __FILE__,__LINE__);
        H5Gclose(h5_pgroup);
        free(h5c_groupname);
        return FAIL;
    }
    ret = H5Gclose(h5_pgroup);
    if(ret < 0) {
        H4toH5error_set(temph4toh5id,3,
             "cannot close parent group interface",
             __FILE__,__LINE__);
        free(h5c_groupname);
        return FAIL;
    }
    free(h5c_groupname);
    return SUCCEED;
}

/*-------------------------------------------------------------------------
 * Function:    H4toH5adv_group
 *
 * Purpose:     convert the vgroup and its members into hdf5 group
                        and hdf5 datasets.
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id: h4toh5 identifier
        vgroup_id: hdf4 vgroup id
        h5pargroupname: absolute path of hdf5 parent group 
        h5chigroupname: absolute path of hdf5 child group 
   Out:

   Modification:
 *-------------------------------------------------------------------------
 */ 

int H4toH5adv_group(hid_t h4toh5_id,
             int32 vgroup_id,
             char* h5pargroupname,
             char* h5chi_groupname,
                int  attr_flag) 
{

    int32       vgroup_tag; /* Vgroup tag */
    int32       vgroup_ref;  /* Vgroup reference number */
    char*        vgroup_class; /* Vgroup class name */
    char*        vgroup_name;  /* Vgroup name */
    uint16  vclassnamelen; /*Vgroup class name length */
    uint16  vgroupnamelen; /*Vgroup name length */
    char*       h5c_groupname; /* The absolute path of HDF5 group name */
    char*       ori_h5cgroup_name; /* The original path of HDF5 group name */

    int         check_tabst; /* the variable to check the table status */
    hid_t       h5_pgroup; /* The absolute path of HDF5 parent group */
    hid_t       h5_cgroup; /* The absolute path of HDF5 children group */
    int         check_groupname; /* The variable to check whether the group name is 
                        used    */
    int         check_vgroup; /* A variable to check whether the group is used */
    int*        check_lookupptr; /* A pointer to pass the flag about the group status */
    int         temp;
    int         temp_flag;
    herr_t  ret;    /* the flag to check the "return" status of HDF5 APIs. */

    /* define h4toh5 temporary variable. */
    h4toh5id_t* temph4toh5id; /*    pointer to h4toh5 id struct for 
                passing parameters of error handlings */
    check_groupname = 0;
    temp                        = 0;
    temp_flag               = -1;
    check_lookupptr = &temp;

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

    /*zeroing out memory for vgroup_class and vgroup_name */

    if(Vgetnamelen(vgroup_id,&vgroupnamelen) == FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup name length",
                                                       __FILE__,__LINE__);
        return FAIL;
    }

    vgroup_name = (char*) malloc((int)(vgroupnamelen+1)*sizeof(char));
    if(vgroup_name == NULL) {
        H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                                                        __FILE__,__LINE__);
        return FAIL;
    }

    if(Vgetclassnamelen(vgroup_id,&vclassnamelen) == FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup name length",
                                                       __FILE__,__LINE__);
        free(vgroup_name);
        return FAIL;
    }

    vgroup_class = (char*) malloc((int)(vclassnamelen+1)*sizeof(char));
    if(vgroup_class == NULL) {
        H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                                                __FILE__,__LINE__);
        free(vgroup_name);
        return FAIL;
    }

    vgroup_tag = VQuerytag(vgroup_id);
    if(vgroup_tag == FAIL) {
        H4toH5error_set(temph4toh5id,2,
             "unable to obtain Vgroup tag",
             __FILE__,__LINE__);
        free(vgroup_name);
        free(vgroup_class);
        return FAIL;
    }

    vgroup_ref = VQueryref(vgroup_id);
    if(vgroup_ref == FAIL) {
        H4toH5error_set(temph4toh5id,2,
             "unable to obtain Vgroup reference",
             __FILE__,__LINE__);
        free(vgroup_name);
        free(vgroup_class);
        return FAIL;
    }

    if(Vgetname(vgroup_id,vgroup_name) == FAIL) {
        H4toH5error_set(temph4toh5id,2,
             "unable to obtain Vgroup name",
             __FILE__,__LINE__);
        free(vgroup_name);
        free(vgroup_class);
        return FAIL;
    }

    if(Vgetclass(vgroup_id,vgroup_class) == FAIL) {
         H4toH5error_set(temph4toh5id,2,
             "unable to obtain Vgroup class name",
             __FILE__,__LINE__);
        free(vgroup_name);
        free(vgroup_class);
        return FAIL;
    }

    /*** ignore reserved HDF group ***/

    if(vgroup_class != NULL) {
        if(strcmp(vgroup_class,_HDF_ATTRIBUTE)==0) {
                free(vgroup_class);
                free(vgroup_name);
                return SUCCEED;
        }
        if(strcmp(vgroup_class,_HDF_VARIABLE) ==0) {
                free(vgroup_class);
                free(vgroup_name);
                return SUCCEED;
        }
        if(strcmp(vgroup_class,_HDF_DIMENSION)==0) {
                free(vgroup_class);
                free(vgroup_name);
                return SUCCEED;
        }
        if(strcmp(vgroup_class,_HDF_UDIMENSION)==0) {
                free(vgroup_class);
                free(vgroup_name);
                return SUCCEED;
        }
        if(strcmp(vgroup_class,_HDF_CDF)==0) {
                free(vgroup_class);
                free(vgroup_name);
                return SUCCEED;
        }
        if(strcmp(vgroup_class,GR_NAME)==0) {
                free(vgroup_class);
                free(vgroup_name);
                return SUCCEED;
        }
        if(strcmp(vgroup_class,RI_NAME)==0) {
                free(vgroup_class);
                free(vgroup_name);
                return SUCCEED;
        }
    }
     
    free(vgroup_class);
    if(vgroup_name != NULL)  {
        if(strcmp(vgroup_name,GR_NAME)==0) {
            free(vgroup_name);
            return SUCCEED;
        }
    }

    /* obtaining the parent group id and the current 
         absolute path of the group name.*/
     
    h5_pgroup = get_h5groupid(h5pargroupname,h4toh5_id,attr_flag);
    if(h5_pgroup <0) {
        H4toH5error_set(temph4toh5id,5,
             "unable to obtain HDF5 group id",
             __FILE__,__LINE__);
        free(vgroup_name);
        return FAIL;
    }

    check_vgroup = lookup(h4toh5_id,vgroup_ref,VG_HASHSIZE,
            temph4toh5id->vg_hashtab,&temp_flag);
    /* obtaining the absolute path of the converted group */
    if(h5chi_groupname == NULL) {

         /* 
             1) Assume the user will not use HDF4_VG_REF as their own 
                    group name. 
             2) Check whether this vgroup was looked up or not. If this vgroup 
                    has been looked up, it must be assigned a name. 
        lookup_name is used to make sure the obtained name is not used 
        before. 
        */

        h5c_groupname = get_h5datasetname(h4toh5_id,h5pargroupname,vgroup_name,
                            (uint16)vgroup_ref,HDF4_VGROUP,OBJECT_HASHSIZE,
                            check_lookupptr);
    
        if(h5c_groupname == NULL) {
             H4toH5error_set(temph4toh5id,4,
             "unable to obtain the absolute path of HDF5 child group",
             __FILE__,__LINE__);
            free(vgroup_name);
            H5Gclose(h5_pgroup);
            return FAIL;
        }

        if(lookup_name(h4toh5_id,h5c_groupname,OBJECT_HASHSIZE,
             temph4toh5id->name_hashtab)==1) {
            H4toH5error_set(temph4toh5id,4,
             "this group name has been used already",
             __FILE__,__LINE__);
            H5Gclose(h5_pgroup);
            free(h5c_groupname);
            free(vgroup_name);
            return FAIL;
        }  
    }
    else {
        h5c_groupname = get_h5datasetname(h4toh5_id,h5pargroupname,
                            h5chi_groupname,(uint16)vgroup_ref,HDF4_VGROUP,
                            OBJECT_HASHSIZE,&check_groupname);
        if(check_groupname == 1) {
             H4toH5error_set(temph4toh5id,4,
             "this group name has been used already",
             __FILE__,__LINE__);
             free(h5c_groupname);
             free(vgroup_name);
             H5Gclose(h5_pgroup);
             return FAIL;
        }
    }

     /*update the HDF5 group name in both object name hash table 
        and group name hash table.*/
    if(lookup_updatename(h4toh5_id,h5c_groupname,OBJECT_HASHSIZE,
                     temph4toh5id->name_hashtab)==-1) {
        H4toH5error_set(temph4toh5id,4,
         "cannot update the name in the name_hashtable",
         __FILE__,__LINE__);
        H5Gclose(h5_pgroup);
        free(h5c_groupname);
        free(vgroup_name);
        return FAIL;
    }
    
    if(lookup_updatename(h4toh5_id,h5c_groupname,NAME_HASHSIZE,
                     temph4toh5id->h5groupname_table)==-1) {
        H4toH5error_set(temph4toh5id,4,
         "cannot update the name in the group_hashtable",
         __FILE__,__LINE__);
        H5Gclose(h5_pgroup);
        free(h5c_groupname);
        free(vgroup_name);
        return FAIL;
    }

    /* if this vgroup had been looked up,
        
        1) build up a hard link.
        2) if the original option(temp_flag) is converting vgroup only,  
             and the current vg_flag is ;
             convert all members of this original vgroup into HDF5 objects.     
             For other combinations, no conversion is made.
    */

    if(check_vgroup == 1) {
        ori_h5cgroup_name = get_name(h4toh5_id,vgroup_ref,VG_HASHSIZE,
                 temph4toh5id->vg_hashtab,&check_groupname);
    
        if(H5Glink(h5_pgroup,H5G_LINK_HARD,ori_h5cgroup_name,h5c_groupname) <0) {
            H4toH5error_set(temph4toh5id,3,
             "cannot create Hard link between groups",
             __FILE__,__LINE__);
            free(h5c_groupname);
            free(ori_h5cgroup_name);
            H5Gclose(h5_pgroup);
            return FAIL;
        }
        free(h5c_groupname);
        free(ori_h5cgroup_name);
        free(vgroup_name);
        H5Gclose(h5_pgroup);
        return SUCCEED;
    }
        
    if(check_vgroup == 0) { 
            
        check_tabst = set_name(h4toh5_id,vgroup_ref,VG_HASHSIZE,
                 temph4toh5id->vg_hashtab,h5c_groupname,1);

        if(check_tabst == FAIL) {
            H4toH5error_set(temph4toh5id,1,
             "Don't have enough memory to allocate for vgroup name",
             __FILE__,__LINE__);
            free(vgroup_name);
            free(h5c_groupname);
            H5Gclose(h5_pgroup);
            return FAIL;
        }
    }

#ifdef HAVE_LIBHDFEOS
    if (H4toH5config_use_eos2_conversion())
        H4toH5eos_add_mangled_vgroupname(h4toh5_id, vgroup_name, h5c_groupname);
#endif
        
    free(vgroup_name);
    h5_cgroup = H4toH5_H5Gcreate(h4toh5_id,h5_pgroup,h5c_groupname,0,attr_flag);
    
    if(h5_cgroup < 0) {
        H4toH5error_set(temph4toh5id,3,
             "cannot create HDF5 group",
             __FILE__,__LINE__);
        H5Gclose(h5_pgroup);
        free(h5c_groupname);
        return FAIL;
    }

    /* vgroup attributes into corresponding hdf5 group attributes.*/
 
    if(vg_transattrs(h4toh5_id,vgroup_id,h5_cgroup,attr_flag)==FAIL) {
        H4toH5error_set(temph4toh5id,5,
         "cannot convert vgroup attributes into HDF5 group attributes",
             __FILE__,__LINE__);
        H5Gclose(h5_cgroup);
        H5Gclose(h5_pgroup);
        free(h5c_groupname);
        return FAIL;
    }

    if(H4toH5anno_obj_all_labels(h4toh5_id,h5pargroupname,h5c_groupname,
                    (uint16)vgroup_ref,vgroup_tag)==FAIL) {
        H4toH5error_set(temph4toh5id,5,
         "cannot obtain label annotation of the vgroup",
         __FILE__,__LINE__);
        H5Gclose(h5_cgroup);
        H5Gclose(h5_pgroup);
        free(h5c_groupname);
        return FAIL;
    }

    if(H4toH5anno_obj_all_descs(h4toh5_id,h5pargroupname,h5c_groupname,
                    (uint16)vgroup_ref,vgroup_tag)==FAIL) {
        H4toH5error_set(temph4toh5id,5,
         "cannot obtain desc annotation of the vgroup",
         __FILE__,__LINE__);
        H5Gclose(h5_cgroup);
        H5Gclose(h5_pgroup);
        free(h5c_groupname);
        return FAIL;
    }
        /* every number of this vgroup will be converted into HDF5 objects.*/
    if(convert_vgroupobjects(h4toh5_id,h5c_groupname,vgroup_id,1,attr_flag)==FAIL){
        H4toH5error_set(temph4toh5id,5,
             "cannot convert vgroup objects",
             __FILE__,__LINE__);
        H5Gclose(h5_cgroup);
        H5Gclose(h5_pgroup);
        free(h5c_groupname);
        return FAIL;
    }
    ret = H5Gclose(h5_cgroup);
    if(ret < 0) {
        H4toH5error_set(temph4toh5id,3,
             "cannot close child group interface",
             __FILE__,__LINE__);
        H5Gclose(h5_pgroup);
        free(h5c_groupname);
        return FAIL;
    }
    ret = H5Gclose(h5_pgroup);
    if(ret < 0) {
        H4toH5error_set(temph4toh5id,5,
             "cannot close parent group interface",
             __FILE__,__LINE__);
        free(h5c_groupname);
        return FAIL;
    }
    free(h5c_groupname);

    return SUCCEED;
}
/*-------------------------------------------------------------------------
 * Function:    convert_vgroup 
 *
 * Purpose:     subroutine to be called by H4toH5adv_group
 *              In this routine, 
                1) h5 vgroup name is obtained;
                2) H4toH5adv_group is called again for 
                 unvisited vgroups
                3) HardLink is created for visited vgroups

 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id: h4toh5 identifier
        obj_ref: object reference number
        h5pgroup_name: h5 parent group name

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

int convert_vgroup(hid_t h4toh5_id,
             int32 obj_ref,
             char* h5pgroup_name,
             int attr_flag)
{
    
    int32       vgroup_cid; /* Vgroup id */
    int32       istat; /* The flag to check the return status of HDF4 APIs */
    char*        cvgroup_name; /* the child vgroup name */
    uint16  vgroupnamelen; /*Vgroup name length */ 

    h4toh5id_t* temph4toh5id; /*    pointer to h4toh5 id struct for 
                passing parameters of error handlings */
 
    temph4toh5id = H4TOH5I_object(h4toh5_id);
    vgroup_cid = Vattach(temph4toh5id->file_id,obj_ref,"r");
    if(vgroup_cid == FAIL) {
        H4toH5error_set(temph4toh5id,2,
             "fail to obtain vgroup id ",
             __FILE__,__LINE__);
        return FAIL;
    }

    if(Vgetnamelen(vgroup_cid,&vgroupnamelen) == FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup name length",
                                                      __FILE__,__LINE__);
        return FAIL;
    }
    
    cvgroup_name = (char*) malloc((int)(vgroupnamelen+1)*sizeof(char));
    if(cvgroup_name == NULL) {
        H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                                                      __FILE__,__LINE__);
                 return FAIL;
    }
 
    /* recursively obtain information from the group*/
    /* check whether it is looked up, if yes, create a hard link.*/
    istat = Vgetname(vgroup_cid,cvgroup_name);
    if(istat == FAIL) {
        H4toH5error_set(temph4toh5id,2,
             "fail to get the name of vgroup ",
             __FILE__,__LINE__);
        Vdetach(vgroup_cid);
        free(cvgroup_name);
        return FAIL;
    }

    if(H4toH5adv_group(h4toh5_id,vgroup_cid,h5pgroup_name,cvgroup_name,attr_flag)==FAIL) {
        H4toH5error_set(temph4toh5id,5,
             "fail to convert the vgroup and all members into HDF5 ",
             __FILE__,__LINE__);
        Vdetach(vgroup_cid);
        free(cvgroup_name);
        return FAIL;
    }
 
    istat = Vdetach(vgroup_cid);
    if(istat == FAIL) {
        H4toH5error_set(temph4toh5id,2,
             "fail to detach vgroup ",
             __FILE__,__LINE__);
        free(cvgroup_name);
        return FAIL;
    }
    free(cvgroup_name);
    return SUCCEED;
}

/*------------------------------------------------------------------
 * Function:    convert_vdata 
 *
 * Purpose:     subroutine to be called by H4toH5bas_vgroup and 
                H4toH5adv_group
 *              In this routine, 
                1) HDF5 vdata name is obtained;
                2) H4toH5vdata is called for
                        unvisited vdatas
                3) HardLink is created for visited vdatas

 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id: h4toh5 identifier
        obj_ref: object reference number
        h5pgroup_name: HDF5 parent group name

 *------------------------------------------------------------------
 */ 
    
int convert_vdata(hid_t h4toh5_id,
            int32 obj_ref,
            char* h5pgroup_name,
            int attr_flag)
{
    
    int32 vdata_id; /* Vdata id */
    int32 file_id; /* HDF4 file id */
    int32       istat; /* a flag to check the "return" status of HDF4 interfaces. */
    
    /* define h4toh5 temporary variable. */
    h4toh5id_t* temph4toh5id; /*    pointer to h4toh5 id struct for 
                passing parameters of error handlings */


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

    /* obtain vdata id */
    vdata_id = VSattach(file_id,obj_ref,"r");
    if(vdata_id == FAIL) {
        H4toH5error_set(temph4toh5id,2,
             "fail to obtain Vdata id",
             __FILE__,__LINE__);
        return FAIL;
    }

/* independent vdata, do the conversion */
    if(H4toH5vdata(h4toh5_id,vdata_id,h5pgroup_name,NULL,attr_flag)== FAIL){
        H4toH5error_set(temph4toh5id,5,
         "fail to convert Vdata into HDF5 dataset ",
         __FILE__,__LINE__);
        VSdetach(vdata_id);
        return FAIL;
    }
    istat = VSdetach(vdata_id);
    if(istat == FAIL) {
        H4toH5error_set(temph4toh5id,2,
         "fail to detach Vdata ",
         __FILE__,__LINE__);
        return FAIL;
    }
    return SUCCEED;
}

/*-------------------------------------------------------------------------
 * Function:    convert_sds
 *
 * Purpose:     subroutine interface to be called by H4toH5bas_vgroup and 
                                H4toH5adv_group.
 *              In this routine, 
                1) HDF5 sds name is obtained;
                2) H4toH5sds is called 
                3) attr_flag will be passed to H4toH5sds 
                   routine.
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id: h4toh5 interface handler
        obj_ref: object reference number
        h5pgroup_name: the absolute path of the parent group
        attr_flag: a flag to indicate whether attributes of
        the sds should be converted

 *-------------------------------------------------------------------------
 */ 
int convert_sds(hid_t h4toh5_id,
        int32 obj_ref,
        char* h5pgroup_name,
        int     attr_flag)
{

    int32 sds_index; /* SDS index */
    int32 sds_id; /* SDS id */
    int32 istat; /* the flag to check the "return" status of HDF4 interfaces.*/

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

    temph4toh5id = H4TOH5I_object(h4toh5_id);

    sds_index = SDreftoindex(temph4toh5id->sd_id,obj_ref);
    if(sds_index == FAIL){
         H4toH5error_set(temph4toh5id,2,
             "fail to obtain index of SDS ",
             __FILE__,__LINE__);
        return FAIL;
    }

    sds_id = SDselect(temph4toh5id->sd_id,sds_index);
    if(sds_id == FAIL){
         H4toH5error_set(temph4toh5id,2,
             "fail to obtain SDS id ",
             __FILE__,__LINE__);
        return FAIL;
    }

    if(H4toH5sds(h4toh5_id,sds_id,h5pgroup_name,NULL,NULL,1,attr_flag)==FAIL){
        H4toH5error_set(temph4toh5id,5,
             "fail to convert this SDS object into an HDF5 dataset",
             __FILE__,__LINE__);
        SDendaccess(sds_id);
        return FAIL;
    }

    istat = SDendaccess(sds_id);
    if(istat == FAIL) {
        H4toH5error_set(temph4toh5id,2,
             "fail to close the SDS interface",
             __FILE__,__LINE__);
        return FAIL;
    }
    return SUCCEED;
}

/*-------------------------------------------------------------------------
 * Function:    convert_image 
 *
 * Purpose:     subroutine interface to be called by H4toH5adv_group 
                and H4toH5bas_vgroup
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id: h4toh5 handler
        obj_ref: object reference number
        h5pgroup_name: h5 group name
        attr_flag: a flag to indicate whether attributes 
        should be converted

 *-------------------------------------------------------------------------
 */ 
int convert_image(hid_t h4toh5_id,
            int32 obj_ref,
            char * h5pgroup_name,
            int attr_flag)
{

    int32       gr_id; /* GR interface id */
    int32       ri_index; /* raster image index */
    int32       ri_id; /* raster image id */
    int32       istat; /* The flag to check the return status of HDF4 APIs */
    h4toh5id_t* temph4toh5id; /*    pointer to h4toh5 id struct for 
                passing parameters of error handlings */
    

    temph4toh5id = H4TOH5I_object(h4toh5_id);

#if 0
    gr_id = GRstart(temph4toh5id->file_id);
    if(gr_id == FAIL) {
         H4toH5error_set(temph4toh5id,2,
             "fail to start GR interface ",
             __FILE__,__LINE__);
        return FAIL;
    }
#endif

    gr_id = temph4toh5id->gr_id;
    ri_index= GRreftoindex(gr_id,(uint16)obj_ref);
    if(ri_index == FAIL) {
         H4toH5error_set(temph4toh5id,2,
             "fail to obtain raster image index ",
             __FILE__,__LINE__);
        GRend(gr_id);
        return FAIL;
    }

    ri_id = GRselect(gr_id,ri_index);
    if(ri_id == FAIL) {
         H4toH5error_set(temph4toh5id,2,
             "fail to obtain raster image id",
             __FILE__,__LINE__);
        GRend(gr_id);
        return FAIL;
    }
    
    if(H4toH5image(h4toh5_id,ri_id,h5pgroup_name,NULL,NULL,NULL,attr_flag,1)==FAIL) {
         H4toH5error_set(temph4toh5id,5,
             "fail to convert an HDF4 image into an HDF5 dataset ",
             __FILE__,__LINE__);
        GRend(gr_id);
        return FAIL;
    }
    
    istat = GRendaccess(ri_id);
    if(istat == FAIL) {
         H4toH5error_set(temph4toh5id,5,
             "fail to close GR interface ",
             __FILE__,__LINE__);
         return FAIL;
    }

    return SUCCEED;
}

/*-------------------------------------------------------------------------
 * Function:    convert_vgroupobjects 
 *
 * Purpose:     subroutine interface for better modularity of H4toH5adv_group 
                and H4toH5bas_vgroup; converting all vgroup objects into
                HDF5 group members.
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id: h4toh5 handler
        h5groupfullpath: full path of HDF5 group
        vgroup_id: vgroup id
        vg_convflag: child vgroup conversion flag
        attr_flag: a flag to indicate whether attributes 
        should be converted

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


int convert_vgroupobjects(hid_t h4toh5_id,
                char *h5groupfullpath,
                int32 vgroup_id,
                int vg_convflag,
                int attr_flag)
{

    int i;
    int num_gobjects; /* number of global objects */
    int32 obj_tag; /* object tag */
    int32 obj_ref;/* object reference */
    h4toh5id_t* temph4toh5id; /*    pointer to h4toh5 id struct for 
                passing parameters of error handlings */
 
    temph4toh5id = H4TOH5I_object(h4toh5_id);

    num_gobjects = Vntagrefs(vgroup_id);
    if(num_gobjects == FAIL) {
         H4toH5error_set(temph4toh5id,2,
             "fail to obtain number of objects in the vgroup ",
             __FILE__,__LINE__);
        return FAIL;
    }

    for( i = 0;i<num_gobjects;i++) { 
            
        if(Vgettagref(vgroup_id,i,&obj_tag,&obj_ref)==FAIL) {
             H4toH5error_set(temph4toh5id,2,
             "fail to obtain object tag and ref. of Vgroup members",
             __FILE__,__LINE__);
            return FAIL;
        }

        if (Visvg(vgroup_id,obj_ref) && vg_convflag != 0 ) {
            if(convert_vgroup(h4toh5_id,obj_ref,h5groupfullpath,attr_flag)== FAIL) {
                H4toH5error_set(temph4toh5id,5,
                        "fail to convert vgroup into HDF5 group ",
                        __FILE__,__LINE__);
                return FAIL;
            }
        }

        else if(Visvs(vgroup_id,obj_ref)) {
            if(convert_vdata(h4toh5_id,obj_ref,h5groupfullpath,attr_flag)==FAIL) {
                H4toH5error_set(temph4toh5id,5,
                        "fail to convert Vdata into HDF5 dataset ",
                        __FILE__,__LINE__);
                return FAIL;
            }
        }

        else if(obj_tag == DFTAG_NDG || obj_tag == DFTAG_SDG) {
            if(convert_sds(h4toh5_id,obj_ref,h5groupfullpath,attr_flag)==FAIL) {
                H4toH5error_set(temph4toh5id,5,
                        "fail to convert SDS into HDF5 dataset ",
                        __FILE__,__LINE__);
                return FAIL;
            }
        }

        else if(obj_tag == DFTAG_RIG) {
            if(convert_image(h4toh5_id,obj_ref,h5groupfullpath,attr_flag)==FAIL){
                H4toH5error_set(temph4toh5id,5,
                        "fail to convert image into HDF5 dataset ",
                        __FILE__,__LINE__);
                return FAIL;
            }
        }
    }
    return SUCCEED;
}

/*-------------------------------------------------------------------------
 * Function:    vg_transattrs
 *
 * Purpose:     translate vgroup attributes into HDF5 attributes
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4vg: HDF4 vgroup id
        h5g:    HDF5 group id
 
 *-------------------------------------------------------------------------
 */ 

int vg_transattrs(hid_t h4toh5_id,
            int32 h4vg,
            hid_t h5g,
            int attr_flag)
{

    /* define variables for hdf4. */
    char*            vgroup_name; /* vgroup name */
    char*            vgroup_class; /* vgroup class name */
    uint16  vclassnamelen; /*Vgroup class name length */
    uint16  vgroupnamelen; /*Vgroup name length */

    char            vgattr_name[H4H5_MAX_NC_NAME]; /* vgroup attribute name */
    char            objtype[H4H5_MAX_NC_NAME]; /* object type name */

    int32           vgroup_cref; /* child vgroup reference number */
    int32           num_vgattr; /* number of vgroup attributes */
    int32           count_vgattr; /* number of elements of each vgroup attribute */
    int32           vg_atype; /* vgroup attribute data type */
    int32           attr_size; /* attribute size */

    size_t      sh4_size; /* size of HDF4 data type in disk */
    size_t      sh4_amemsize; /* size of HDF4 data type in memory */

     /* define variables for hdf5. */
    hid_t           sh5a_sid; /* HDF5 attribute space id */
    hid_t           sh5a_id; /* HDF5 attribute id */
    hid_t           sh5_atype; /*HDF5 attribute data type in disk */
    hid_t           sh5_amemtype; /* HDF5 attribute data type in memory */
    hid_t           sh5str_type; /* HDF5 file attribute data type in string format */
    hid_t           sh5str_memtype; /*HDF5 memory attribute data type in string format*/
    hsize_t     sh5dims[1];/*size of the dimension of HDF5 vgroup attribute */
    void*           vg_adata; /* vgroup attribute data */
    herr_t      sret; /* the flag to check the "return" status of HDF5 APIs. */
     int             i;
     
    h4toh5id_t* temph4toh5id; /*    pointer to h4toh5 id struct for 
                passing parameters of error handlings */

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

    if(Vgetnamelen(h4vg,&vgroupnamelen) == FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup name length",
                                                            __FILE__,__LINE__);
        return FAIL;
    }

    vgroup_name = (char*) malloc((int)(vgroupnamelen+1)*sizeof(char));
    if(vgroup_name == NULL) {
        H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                                              __FILE__,__LINE__);
        return FAIL;
    }

    if(Vgetclassnamelen(h4vg,&vclassnamelen) == FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup name length",
                                              __FILE__,__LINE__);
        free(vgroup_name);
        return FAIL;
    }

    vgroup_class = (char*) malloc((int)(vclassnamelen+1)*sizeof(char));
    if(vgroup_class == NULL) {
        H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                                              __FILE__,__LINE__);
        free(vgroup_name);
        return FAIL;
    }

    /* ignore CDF0.0 and RIG0.0 vgroups. */
    if(Vgetclass(h4vg,vgroup_class) == SUCCEED){
        if(vgroup_class[0] != '\0') {
            if(!strcmp(vgroup_class,_HDF_CDF)||
                !strcmp(vgroup_class,GR_NAME)) {
                free(vgroup_name);
                free(vgroup_class);
                return SUCCEED;
            }
        }
    }

    free(vgroup_class);
    num_vgattr = Vnattrs(h4vg);
    if(num_vgattr < 0) {
         H4toH5error_set(temph4toh5id,2,
             "fail to obtain the number of vgroup attribute ",
             __FILE__,__LINE__);
         free(vgroup_name);
         return FAIL;
    }

    for (i = 0;i <num_vgattr;i++) {

        if (Vattrinfo(h4vg,i,vgattr_name,&vg_atype,
             &count_vgattr,&attr_size)== FAIL){  
            H4toH5error_set(temph4toh5id,2,
             "fail to obtain Vgroup attribute information ",
             __FILE__,__LINE__);
            free(vgroup_name);
            return FAIL;
        }

        /* convert attribute datatype into the corresponding HDF5 datatype */
        if(h4type_to_h5type(h4toh5_id,vg_atype,&sh5_amemtype,&sh4_amemsize,
            &sh4_size,&sh5_atype)==FAIL){
            H4toH5error_set(temph4toh5id,5,
            "cannot convert HDF4 data type to HDF5 data type",
            __FILE__,__LINE__);
            free(vgroup_name);
            return FAIL;
        }

        vg_adata = malloc(sh4_amemsize*count_vgattr);
        if(vg_adata == NULL) {
            H4toH5error_set(temph4toh5id,1,
            "cannot allocate memory for Vgroup attribute data",
            __FILE__,__LINE__);
            free(vgroup_name);
            return FAIL;
        }

        if(Vgetattr(h4vg,i,(VOIDP)vg_adata)==FAIL){
            H4toH5error_set(temph4toh5id,2,
            "cannot obtain Vgroup attribute",
            __FILE__,__LINE__);
            free(vgroup_name);
            free(vg_adata);
            return FAIL;
        }

        /* if the attribute doesn't have a name, a default name is set. */
        if(vgattr_name[0] == '\0') 
            strcpy(vgattr_name,trans_obj_name(h4toh5_id,DFTAG_VG,i));

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

            sh5a_sid = H5Screate(H5S_SCALAR);
            if (sh5a_sid < 0) {
                 H4toH5error_set(temph4toh5id,3,
                     "cannot create attribute space",
                     __FILE__,__LINE__);
                free(vgroup_name);
                free(vg_adata);
                return FAIL;
            }
 
            if ((sh5str_type = mkstr(h4toh5_id,count_vgattr*sh4_size,H5T_STR_NULLTERM))<0) {
                 H4toH5error_set(temph4toh5id,3,
                     "cannot make HDF5 string type for Vgroup attribute",
                     __FILE__,__LINE__);
                 H5Sclose(sh5a_sid);
                 free(vgroup_name);
                 free(vg_adata);
                 return FAIL;
            }
 
                 
            if ((sh5str_memtype = mkstr(h4toh5_id,count_vgattr*sh4_amemsize,
                         H5T_STR_NULLTERM))<0){
                 H4toH5error_set(temph4toh5id,3,
                      "cannot make HDF5 string memory type for Vgroup attribute",
                      __FILE__,__LINE__);
                 H5Sclose(sh5a_sid);
                 free(vgroup_name);
                 free(vg_adata);
                 return FAIL;
            }
 
            sh5a_id = H5Acreate_safe(h4toh5_id,h5g,vgattr_name,sh5str_type,sh5a_sid,H5P_DEFAULT);

            if (sh5a_id <0) {
                if (transattrs_split(h4toh5_id, h5g, vgattr_name, sh5a_sid, vg_adata, count_vgattr) < 0) {
                    H4toH5error_set(temph4toh5id,3,
                                    "fail to obtain HDF5 attribute id",
                                    __FILE__,__LINE__);
                    H5Sclose(sh5a_sid);
                    free(vgroup_name);
                    free(vg_adata);
                    return FAIL;
                }
            }
            else if (H5Awrite(sh5a_id,sh5str_memtype,(void *)vg_adata) < 0) {
                H4toH5error_set(temph4toh5id,3,
                     "cannot write HDF5 attribute data",
                     __FILE__,__LINE__);
                H5Sclose(sh5a_sid);
                H5Aclose(sh5a_id);
                free(vgroup_name);
                free(vg_adata);
                return FAIL;
            }
        }
        else {
             if (!H4toH5config_use_netcdf4_hack() && count_vgattr == 1) {
                sh5a_sid = H5Screate(H5S_SCALAR);
                if (sh5a_sid < 0) {
                    H4toH5error_set(temph4toh5id,3,
                     "cannot create HDF5 space id",
                     __FILE__,__LINE__);
                    free(vgroup_name);
                    free(vg_adata);
                    return FAIL;
                }
             }

             else {
                 
                sh5dims[0] = count_vgattr;
                sh5a_sid =  H5Screate_simple(1,sh5dims,NULL);
                if (sh5a_sid < 0)  {
                    H4toH5error_set(temph4toh5id,3,
                        "cannot create HDF5 attribute space id",
                        __FILE__,__LINE__);
                    free(vgroup_name);
                    free(vg_adata);
                    return FAIL;
                }
             }

             sh5a_id = H5Acreate_safe(h4toh5_id,h5g,vgattr_name,sh5_atype,sh5a_sid,H5P_DEFAULT);

             if(sh5a_id <0) {
                 H4toH5error_set(temph4toh5id,3,
                         "cannot obtain HDF5 attribute id",
                         __FILE__,__LINE__);
                 free(vgroup_name);
                 free(vg_adata);
                 H5Sclose(sh5a_sid);
                 return FAIL;
             }
             sret = H5Awrite(sh5a_id,sh5_amemtype,(void *)vg_adata);

             if(sret < 0) {
                 H4toH5error_set(temph4toh5id,3,
                         "cannot write HDF5 attribute data",
                         __FILE__,__LINE__);
                 free(vgroup_name);
                 free(vg_adata);
                 H5Sclose(sh5a_sid);
                 H5Aclose(sh5a_id);
                 return FAIL;
             }

         }

         sret = H5Sclose(sh5a_sid);
         if(sret < 0) {
             H4toH5error_set(temph4toh5id,3,
             "cannot close HDF5 attribute data space ",
             __FILE__,__LINE__);
             free(vgroup_name);
             free(vg_adata);
             H5Aclose(sh5a_id);
             return FAIL;
         }
         if (sh5a_id >= 0) {
             sret = H5Aclose(sh5a_id);
             if(sret < 0) {
                 H4toH5error_set(temph4toh5id,3,
                             "cannot close HDF5 attribute interface",
                             __FILE__,__LINE__);
                 free(vgroup_name);
                 free(vg_adata);
                 return FAIL;
             }
         }
         free(vg_adata);
    }
    
     /*** check this line later. ***/
    strcpy(objtype,VGROUPLABEL);
    /*   vgroup_class[0] = '\0';*/

    /* transfer predefined attributes. */
    if(attr_flag == H425_OSPEC_ALLATTRS || attr_flag == H425_ALLATTRS){
        if(h4_transpredattrs(h4toh5_id,h5g,HDF4_OBJECT_TYPE,objtype)==FAIL){
            H4toH5error_set(temph4toh5id,5,
                "cannot convert HDF4 predefined attribute OBJECT_TYPE ",
                __FILE__,__LINE__);
            free(vgroup_name);
            return FAIL;
        }
   
        if(Vgetname(h4vg,vgroup_name) == SUCCEED){
            if(vgroup_name[0] != '\0') {
                if(h4_transpredattrs(h4toh5_id,h5g,HDF4_OBJECT_NAME,vgroup_name)==FAIL){
                    H4toH5error_set(temph4toh5id,5,
                           "cannot convert HDF4 predefined attribute OBJECT_NAME",
                           __FILE__,__LINE__);
                    free(vgroup_name);
                    return FAIL;
                }
            }
        }
    
        vgroup_cref = VQueryref(h4vg);
        if(vgroup_cref == FAIL) {
            H4toH5error_set(temph4toh5id,3,
                "cannot obtain vgroup reference number",
                __FILE__,__LINE__);
            free(vgroup_name);
            return FAIL;
        }
   
        if(h4_transnumattr(h4toh5_id,h5g,HDF4_REF_NUM,(uint16)vgroup_cref)==FAIL){
            H4toH5error_set(temph4toh5id,5,
                "cannot convert HDF4 predefined attribute Reference number",
                __FILE__,__LINE__);
            free(vgroup_name);
            return FAIL;
        }
    }
    free(vgroup_name);
    return SUCCEED;
}

/*-------------------------------------------------------------------------
 * Function:    H4toH5vgroupattrname
 *
 * Purpose:     translate a vgroup attribute into an hdf5 attribute, 
                the attribute name is used as the key to find the approprite
                attribute
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id:                  h4toh5 identifier
        h4vg:                       hdf4 vgroup id
        h5pargroupfullpath: parent group full path
        h5groupname:                relative group name to h5pargroupfullpath
        attrname:                       hdf4 attribute name 
        
 *
 *-------------------------------------------------------------------------
 */ 
int H4toH5vgroup_attr_name(hid_t h4toh5_id,
                int32 h4vg,
                char* h5pargroupfullpath,
                char* h5groupname,
                char* attrname)
{
    intn h4_index; /*HDF4 attribute index */

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

    temph4toh5id = H4TOH5I_object(h4toh5_id);

    /* find HDF4 attribute index. */
    h4_index = Vfindattr(h4vg,attrname);
    if(h4_index == FAIL) {
         H4toH5error_set(temph4toh5id,5,
                 "cannot convert HDF4 vgroup attribute by name",
                 __FILE__,__LINE__);
        return FAIL;
    }

    /* calling attribute conversion routine with the index as the key. */
    if(H4toH5vgroup_attr_index(h4toh5_id,h4vg,h5pargroupfullpath,h5groupname,h4_index)==FAIL){
    H4toH5error_set(temph4toh5id,5,
                 "cannot convert HDF4 vgroup attribute by name",
                 __FILE__,__LINE__);
        return FAIL;
    }
    return SUCCEED;
}
/*-------------------------------------------------------------------------
 * Function:    H4toH5vgroup_attr_index
 *
 * Purpose:     translate a vgroup attribute into an HDF5 attribute,
                                attribute index is used as the key
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id:                  h4toh5 identifier
        h4vg:                               hdf4 vgroup id
        h5pargroupfullpath: parent group full path
        h5groupname:                relative group name to h5pargroupfullpath
        h4_index:                       hdf4 attribute index
        
 *
 *-------------------------------------------------------------------------
 */ 

int H4toH5vgroup_attr_index(hid_t h4toh5_id,
                int32 h4vg,
                char* h5pargroupfullpath,
                char* h5groupname,
                int     h4_index)
{

    /* define variables for hdf4. */
    char*          vgroup_name; /* vgroup name */
    uint16         vgroupnamelen; /*Vgroup name length */
    char*       cor_vgroup_name;
    char            vgattr_name[H4H5_MAX_NC_NAME]; /* vgroup attribute name */
    char            refstr[MAXREF_LENGTH]; /* string format of HDF4 vgroup reference
                            number */
    char*       h5crepvgroup_name; /*temporary variable to represent HDF4 vgroup
                   name */
    char*       h5cvgroup_name; /* The absolute path of HDF4 vgroup name */
    
    int32       vg_ref; /* vgroup reference number */
    int32       count_vgattr; /* number of elements of each vgroup attribute */
    int32       vg_atype; /* vgroup attribute data type */
    int32       attr_size; /* attribute size */

    size_t      sh4_size; /* size of HDF4 data type in disk */
    size_t      sh4_amemsize;  /* size of HDF4 data type in memory */

    /* define variables for hdf5. */
    hid_t       h5_pgroup; /* HDF5 parent group id */
    hid_t       h5g; /* HDF5 group id */
    hid_t       sh5a_sid; /* HDF5 attribute space id */
    hid_t       sh5a_id; /* HDF5 attribute id */
    hid_t       sh5_atype; /*HDF5 attribute data type in disk */
    hid_t       sh5_amemtype; /* HDF5 attribute data type in memory */
    hid_t       sh5str_type; /* HDF5 file attribute data type in string format */
    hid_t       sh5str_memtype; /*HDF5 memory attribute data type in string format*/
    hsize_t     sh5dims[1]; /*size of the dimension of HDF5 vgroup attribute */
    void*       vg_adata; /* vgroup attribute data */
    herr_t      sret; /* the flag to check the "return" status of HDF5 APIs. */
    char*       cor_h5groupname;
    h4toh5id_t* temph4toh5id; /*    pointer to h4toh5 id struct for 
                passing parameters of error handlings */

    temph4toh5id = H4TOH5I_object(h4toh5_id);

    if(Vgetnamelen(h4vg,&vgroupnamelen) == FAIL) {
         H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup name length",
                                                         __FILE__,__LINE__);
         return FAIL;
    }

    vgroup_name = (char*) malloc((int)(vgroupnamelen+1)*sizeof(char));
    if(vgroup_name == NULL) {
        H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                                              __FILE__,__LINE__);
        return FAIL;
    }

    /* obtain group id. */
    h5_pgroup        =  get_h5groupid(h5pargroupfullpath,h4toh5_id,H425_OSPEC_ALLATTRS);
    if(h5_pgroup < 0) {
        H4toH5error_set(temph4toh5id,5,
                 "cannot obtain HDF5 group ID",
                 __FILE__,__LINE__);
        free(vgroup_name);
        return FAIL;
    }

    if(Vgetname(h4vg,vgroup_name)==FAIL){
        H4toH5error_set(temph4toh5id,2,
                 "cannot obtain HDF4 vgroup name",
                 __FILE__,__LINE__);
        free(vgroup_name);
        H5Gclose(h5_pgroup);
        return FAIL;
    }

    if((vg_ref=VQueryref(h4vg))==FAIL){
        H4toH5error_set(temph4toh5id,2,
                 "cannot obtain HDF4 vgroup reference",
                 __FILE__,__LINE__);
        free(vgroup_name);
        H5Gclose(h5_pgroup);
        return FAIL;
    }

    /* obtain the absolute path of HDF5 group */
    if(h5groupname == NULL) {
         /* obtain the absolute path of HDF5 group based on vgroup name. */
        if(conv_int_str(h4toh5_id,(uint16)vg_ref,refstr)== FAIL) {
            H4toH5error_set(temph4toh5id,5,
                     "cannot convert reference number into string type",
                 __FILE__,__LINE__);
            H5Gclose(h5_pgroup);
            free(vgroup_name);
            return FAIL;
        }
        h5crepvgroup_name=make_objname_no(h4toh5_id,refstr,h5pargroupfullpath,
                             HDF4_VGROUP);
        if(lookup_name(h4toh5_id,h5crepvgroup_name,VG_HASHSIZE,
                         temph4toh5id->name_hashtab)==1){
            h5cvgroup_name = malloc(strlen(h5crepvgroup_name)+1);
            if(h5cvgroup_name == NULL) {
                H4toH5error_set(temph4toh5id,1,"cannot allocate memory for vgroup name",
                         __FILE__,__LINE__);
                H5Gclose(h5_pgroup);
                free(vgroup_name);
                return FAIL;
            }
            strncpy(h5cvgroup_name,h5crepvgroup_name,strlen(h5crepvgroup_name)+1);
        }
        else {
            cor_vgroup_name = correct_name(h4toh5_id,vgroup_name);
            if(cor_vgroup_name == NULL){
                H4toH5error_set(temph4toh5id,1,"cannot allocate memory for corrected vgroup name",
                         __FILE__,__LINE__);
                H5Gclose(h5_pgroup);
                free(vgroup_name);
                return FAIL;
            }
            h5cvgroup_name = make_objname_yes(h4toh5_id,cor_vgroup_name,h5pargroupfullpath);
            free(cor_vgroup_name);
        }
        free(h5crepvgroup_name);
    }

    else {
        cor_h5groupname = correct_name(h4toh5_id,h5groupname);
        h5cvgroup_name = make_objname_yes(h4toh5_id,cor_h5groupname,h5pargroupfullpath);
        free(cor_h5groupname);
    }
    h5g  = H5GOPEN(h5_pgroup,h5cvgroup_name);
    free(h5cvgroup_name);
    free(vgroup_name);


     /* obtain vgroup attribute information*/
    if (Vattrinfo(h4vg,h4_index,vgattr_name,&vg_atype,
        &count_vgattr,&attr_size)== FAIL){  
        H4toH5error_set(temph4toh5id,2,
               "fail to obtain Vgroup attribute information ",
               __FILE__,__LINE__);
        H5Gclose(h5_pgroup);
        return FAIL;
    }

    /* convert attribute datatype into the corresponding HDF5 datatype */
    if(h4type_to_h5type(h4toh5_id,vg_atype,&sh5_amemtype,&sh4_amemsize,
        &sh4_size,&sh5_atype)==FAIL){
        H4toH5error_set(temph4toh5id,5,
        "cannot convert HDF4 data type to HDF5 data type",
        __FILE__,__LINE__);
        H5Gclose(h5_pgroup);
        return FAIL;
    }

    vg_adata = malloc(sh4_amemsize*count_vgattr);

    if(vg_adata == NULL) {

        H4toH5error_set(temph4toh5id,1,
        "cannot allocate memory for Vgroup attribute data",
        __FILE__,__LINE__);
        H5Gclose(h5_pgroup);
        return FAIL;
    }

    if(Vgetattr(h4vg,h4_index,(VOIDP)vg_adata)==FAIL){

        H4toH5error_set(temph4toh5id,2,
        "cannot obtain Vgroup attribute",
        __FILE__,__LINE__);
        free(vg_adata);
        H5Gclose(h5_pgroup);
        return FAIL;
    }

    /* if the attribute doesn't have a name, a default name is set. */
    if(vgattr_name[0] == '\0') 
        strcpy(vgattr_name,trans_obj_name(h4toh5_id,DFTAG_VG,h4_index));

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

        sh5a_sid = H5Screate(H5S_SCALAR);
    
        if (sh5a_sid < 0) {
    
             H4toH5error_set(temph4toh5id,3,
                 "cannot create attribute space",
                 __FILE__,__LINE__);
             H5Gclose(h5_pgroup);
             free(vg_adata);
             return FAIL;
        }
    
        if ((sh5str_type = mkstr(h4toh5_id,count_vgattr*sh4_size,H5T_STR_NULLTERM))<0) {
             H4toH5error_set(temph4toh5id,3,
                 "cannot make HDF5 string type for Vgroup attribute",
                 __FILE__,__LINE__);
             H5Gclose(h5_pgroup);
                H5Sclose(sh5a_sid);
             free(vg_adata);
             return FAIL;
        }

                
        if ((sh5str_memtype = mkstr(h4toh5_id,count_vgattr*sh4_amemsize,
                        H5T_STR_NULLTERM))<0){
            H4toH5error_set(temph4toh5id,3,
                 "cannot make HDF5 string memory type for Vgroup attribute",
                 __FILE__,__LINE__);
            H5Gclose(h5_pgroup);
             H5Sclose(sh5a_sid);
            free(vg_adata);
            return FAIL;
        }

        sh5a_id = H5Acreate_safe(h4toh5_id,h5g,vgattr_name,sh5str_type,sh5a_sid,H5P_DEFAULT);

        if (sh5a_id <0) {
            if (transattrs_split(h4toh5_id, h5g, vgattr_name, sh5a_sid, vg_adata, count_vgattr) < 0) {
                H4toH5error_set(temph4toh5id,3,
                                "fail to obtain HDF5 attribute id",
                                __FILE__,__LINE__);
                H5Gclose(h5_pgroup);
                free(vg_adata);
                return FAIL;
            }
        }
        else if (H5Awrite(sh5a_id,sh5str_memtype,(void *)vg_adata) < 0) {
            H4toH5error_set(temph4toh5id,3,
                 "cannot write HDF5 attribute data",
                 __FILE__,__LINE__);
            free(vg_adata);
             H5Gclose(h5_pgroup);
                H5Sclose(sh5a_sid);
            return FAIL;
        }
    }
     
    else {
            
        if (count_vgattr == 1) {
            sh5a_sid = H5Screate(H5S_SCALAR);
            if (sh5a_sid < 0) {
                   H4toH5error_set(temph4toh5id,3,
                    "cannot create HDF5 space id",
                    __FILE__,__LINE__);
                   free(vg_adata);
                    H5Gclose(h5_pgroup);
                   return FAIL;
            }
        }
        else {
                 
            sh5dims[0] = count_vgattr;
            sh5a_sid =  H5Screate_simple(1,sh5dims,NULL);
            if (sh5a_sid < 0)  {
                H4toH5error_set(temph4toh5id,3,
                    "cannot create HDF5 attribute space id",
                    __FILE__,__LINE__);
                free(vg_adata);
                   H5Gclose(h5_pgroup);
                return FAIL;
            }
        }

        sh5a_id = H5Acreate_safe(h4toh5_id,h5g,vgattr_name,sh5_atype,sh5a_sid,H5P_DEFAULT);

        if(sh5a_id <0) {
            H4toH5error_set(temph4toh5id,3,
                    "cannot obtain HDF5 attribute id",
                    __FILE__,__LINE__);
            free(vg_adata);
            H5Sclose(sh5a_sid);
            H5Gclose(h5_pgroup);
            return FAIL;
        }
        sret = H5Awrite(sh5a_id,sh5_amemtype,(void *)vg_adata);

        if(sret < 0) {
            H4toH5error_set(temph4toh5id,3,
                    "cannot write HDF5 attribute data",
                    __FILE__,__LINE__);
            free(vg_adata);
            H5Sclose(sh5a_sid);
            H5Aclose(sh5a_id);
            H5Gclose(h5_pgroup);
            return FAIL;
        }

    }
    sret = H5Sclose(sh5a_sid);
    if(sret < 0) {
        H4toH5error_set(temph4toh5id,3,
          "cannot write HDF5 attribute data",
           __FILE__,__LINE__);
        free(vg_adata);
        H5Aclose(sh5a_id);
        H5Gclose(h5_pgroup);
        return FAIL;
    }
    if (sh5a_id >= 0) {
        sret = H5Aclose(sh5a_id);
        if(sret < 0) {
            H4toH5error_set(temph4toh5id,3,
             "cannot write HDF5 attribute data",
             __FILE__,__LINE__);
            free(vg_adata);
            H5Gclose(h5_pgroup);
            return FAIL;
        }
    }
    sret = H5Gclose(h5g);
    if(sret < 0) {
        H4toH5error_set(temph4toh5id,3,
                                 "cannot write HDF5 attribute data",
                                 __FILE__,__LINE__);
        free(vg_adata);
        return FAIL;
    }

    sret = H5Gclose(h5_pgroup);
    if(sret < 0) {
        H4toH5error_set(temph4toh5id,3,
             "cannot write HDF5 attribute data",
             __FILE__,__LINE__);
        free(vg_adata);
        return FAIL;
    }
             
    free(vg_adata);
    return SUCCEED;
}


/*-------------------------------------------------------------------------
 * Function:    checkvloneobject
 *
 * Purpose:     check all objects of lone vgroup(including objects of 
                descendent vgroups of this lone vgroup) and mark down these 
                objects
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id:                  h4toh5 identifier
        file_id:                        HDF4 file identifier
Note: this routine will not be used for the time being.
 *
 *-------------------------------------------------------------------------
 */ 


int checkvloneobject(hid_t h4toh5_id,int32 file_id)
{
             
    int32  vgroup_id; /* vgroup id */
    int      num_lonevg; /* number of lone vgroup.*/
    int32  *ref_array; /* array of reference number */
    int32  istat; /* flag to check the "return" status of HDF4 interfaces */
    char*       vgroup_name = NULL; /* vgroup name */
    char*       vgroup_class = NULL; /* vgroup class name */
    uint16  vclassnamelen; /*Vgroup class name length */
    uint16  vgroupnamelen; /*Vgroup name length */
    int      check_vgroup; /* flag to check the vgroup status */
    int      lone_vg_number; /* index to represent the lone vgroup number */

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

    temph4toh5id = H4TOH5I_object(h4toh5_id);

    istat = Vstart(file_id);
    if (istat == FAIL) { 
        H4toH5error_set(temph4toh5id,2,
                 "fail to obtain start V interface",
                 __FILE__,__LINE__);
        return FAIL;
    }

    num_lonevg = Vlone(file_id,NULL,0);
    
    if (num_lonevg == FAIL) {
        H4toH5error_set(temph4toh5id,2,
                 "fail to obtain lone vgroup number",
                 __FILE__,__LINE__);
        return FAIL;
    }

    /* obtain object reference array. */

    /* if no lone vgroup, quit from this function. */
    if(num_lonevg == 0) 
        return SUCCEED;

    ref_array = (int32 *)malloc(sizeof(int32) *num_lonevg);

    if(ref_array == NULL) {
        H4toH5error_set(temph4toh5id,2,
                 "fail to allocate memory for reference array",
                 __FILE__,__LINE__);
        return FAIL;
    }

    num_lonevg = Vlone(file_id,ref_array,num_lonevg);

    /* walk through every lone group in the file */

    for(lone_vg_number = 0; lone_vg_number < num_lonevg;
            lone_vg_number++) {

        vgroup_id = Vattach(file_id,ref_array[lone_vg_number],"r");
        if(vgroup_id ==FAIL) {
            H4toH5error_set(temph4toh5id,2,
                            "fail to obtain vgroup id",
                            __FILE__,__LINE__);
            free(ref_array);
            return FAIL;
        }

        if(Vgetnamelen(vgroup_id,&vgroupnamelen) == FAIL) {
            H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup name length",
                                                          __FILE__,__LINE__);
            free(ref_array);
            Vdetach(vgroup_id);
            return FAIL;
        }

        vgroup_name = (char*) malloc((int)(vgroupnamelen+1)*sizeof(char));
        if(vgroup_name == NULL) {
            H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                                                        __FILE__,__LINE__);
            free(ref_array);
            Vdetach(vgroup_id);
            return FAIL;
        }

        h4toh5_ZeroMemory(vgroup_name,(int)(vgroupnamelen+1)*sizeof(char));

        if(Vgetclassnamelen(vgroup_id,&vclassnamelen) == FAIL) {
            H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup name length",
                                                            __FILE__,__LINE__);
            free(ref_array);
            free(vgroup_name);
            Vdetach(vgroup_id);
            return FAIL;
        }

        vgroup_class = (char*) malloc((int)(vclassnamelen+1)*sizeof(char));
        if(vgroup_class == NULL) {
            H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                                                           __FILE__,__LINE__);
            free(ref_array);
            free(vgroup_name);
            Vdetach(vgroup_id);
            return FAIL;
        }
         
        h4toh5_ZeroMemory(vgroup_class,(int)(vclassnamelen+1)*sizeof(char));

        /*obtain group name and class name.*/
        istat = Vgetclass(vgroup_id,vgroup_class);
        if(istat == FAIL) {
            H4toH5error_set(temph4toh5id,2,
                            "fail to obtain vgroup class name",
                            __FILE__,__LINE__);
            free(ref_array);
            free(vgroup_name);
            free(vgroup_class);
            Vdetach(vgroup_id);
            return FAIL;
        }

        istat = Vgetname(vgroup_id,vgroup_name);
        if(istat == FAIL ) {
            H4toH5error_set(temph4toh5id,2,
                            "fail to obtain vgroup name",
                            __FILE__,__LINE__);
            Vdetach(vgroup_id);
            free(ref_array);
            free(vgroup_name);
            free(vgroup_class);
            return FAIL;
        }

        /* check for CDF0.0 and RIG0.0, if yes
             don't go into this group.*/
                 
        if(strcmp(vgroup_class,_HDF_CDF)==0) {
            free(vgroup_name);
            free(vgroup_class);
            Vdetach(vgroup_id);
            continue;
        }
        if(strcmp(vgroup_class,GR_NAME)==0) {
            free(vgroup_name);
            free(vgroup_class);
            Vdetach(vgroup_id);
            continue;
        }

        /* check vgroup */
        check_vgroup = lookup(h4toh5_id,ref_array[lone_vg_number],VG_HASHSIZE,
                temph4toh5id->vg_hashtab,&temp_flag);

        if(check_vgroup == 0) { /* adding this vgroup into the list. */

            if(vgcheck_object(h4toh5_id,vgroup_id)==FAIL){
                Vdetach(vgroup_id);
                free(vgroup_name);
                free(vgroup_class);
                free(ref_array);
                return FAIL;
            }
        }
        Vdetach(vgroup_id);
        free(vgroup_name);
        free(vgroup_class);
    }
    free(ref_array);
    return SUCCEED;
}

/*-------------------------------------------------------------------------
 * Function:    checkvringobject
 *
 * Purpose:     check all SDS and image objects of every vgroup
                (including objects of 
                descendent vgroups of this lone vgroup) and mark down these 
                objects
                                
                                
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id:                  h4toh5 identifier
        file_id:                        HDF4 file identifier
Note: this function is more general than checkvloneobject
 *
 *-------------------------------------------------------------------------
 */ 

int checkvringobject(hid_t h4toh5id,int32 file_id)
{
    
    int32  vgroup_id; /* vgroup id */
    int32  ref_num; /* reference number */
#if 0
    char*       vgroup_name; /* vgroup name */
    char*       vgroup_class;/* vgroup class name */
    uint16  vclassnamelen; /*Vgroup class name length */
    uint16  vgroupnamelen; /*Vgroup name length */
#endif
    char        vgroup_name[VGNAMELENMAX*4];
    char        vgroup_class[VGNAMELENMAX*4];
    int      check_vgroup; /* flag to check the vgroup */
    int32  istat; /* The flag to check the return status of HDF4 APIs */
    h4toh5id_t* temph4toh5id; /*    pointer to h4toh5 id struct for 
                passing parameters of error handlings */
    int      temp_flag; /* temporary flag */

    temph4toh5id = H4TOH5I_object(h4toh5id);

#if 0
    if(Vgetnamelen(vgroup_id,&vgroupnamelen) == FAIL) {
            H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup name length",
                                                          __FILE__,__LINE__);
            return FAIL;
     }

     vgroup_name = (char*) malloc((int)(vgroupnamelen+1)*sizeof(char));
     if(vgroup_name == NULL) {
            H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                                                           __FILE__,__LINE__);
            return FAIL;
     }

    if(Vgetclassnamelen(vgroup_id,&vclassnamelen) == FAIL) {
            H4toH5error_set(temph4toh5id,2,"cannot obtain vgroup class length",
                                                                             __FILE__,__LINE__);
                                    return FAIL;
    }

    vgroup_class = (char*) malloc((int)(vclassnamelen+1)*sizeof(char));
    if(vgroup_class == NULL) {
                         H4toH5error_set(temph4toh5id,1,"cannot allocate memory",
                                                               __FILE__,__LINE__);
                                    return FAIL;
    }
#endif


    temp_flag = -1;
    ref_num = Vgetid(file_id,-1);

    while (ref_num != -1) {
    
        /* if we find a group that is not touched, grab it under root group.*/

        check_vgroup = lookup(h4toh5id,ref_num,VG_HASHSIZE,
                temph4toh5id->vg_hashtab,&temp_flag);

        if (check_vgroup == 0){

            vgroup_id = Vattach(file_id,ref_num,"r");
            if(vgroup_id ==FAIL) {
                H4toH5error_set(temph4toh5id,2,
                         "fail to get vgroup id",
                         __FILE__,__LINE__);
                return FAIL;
            }

            h4toh5_ZeroMemory(vgroup_name,VGNAMELENMAX*4);
            istat = Vgetname(vgroup_id,vgroup_name);
            if(istat ==FAIL) {
                H4toH5error_set(temph4toh5id,2,
                         "fail to get vgroup name",
                         __FILE__,__LINE__);
                Vdetach(vgroup_id);
                return FAIL;
            }

            h4toh5_ZeroMemory(vgroup_class,VGNAMELENMAX*4);
            if(Vgetclass(vgroup_id,vgroup_class) == FAIL) {
                H4toH5error_set(temph4toh5id,2,
                         "fail to get vgroup class name",
                         __FILE__,__LINE__);
                Vdetach(vgroup_id);
                return FAIL;
            }

            /* do nothing for those predefined vgroups.*/

            if(vgroup_class[0] != '\0') {

                if(strcmp(vgroup_class,_HDF_ATTRIBUTE)==0) {
                    ref_num = Vgetid(file_id,ref_num); 
                    Vdetach(vgroup_id);
                    continue;
                }
            
                if(strcmp(vgroup_class,_HDF_VARIABLE)==0) {
                    ref_num = Vgetid(file_id,ref_num);
                    Vdetach(vgroup_id);
                    continue;
                }
            
                if(strcmp(vgroup_class,_HDF_DIMENSION)==0) {
                    ref_num = Vgetid(file_id,ref_num);
                    Vdetach(vgroup_id);
                    continue;
                }
            
                if(strcmp(vgroup_class,_HDF_UDIMENSION)==0) {
                    ref_num = Vgetid(file_id,ref_num);
                    Vdetach(vgroup_id);
                    continue;
                }
            
                if(strcmp(vgroup_class,_HDF_CDF)==0) {
                    ref_num = Vgetid(file_id,ref_num);
                    Vdetach(vgroup_id);
                    continue;
                }
            
                if(strcmp(vgroup_class,GR_NAME)==0)  {
                    ref_num = Vgetid(file_id,ref_num);
                    Vdetach(vgroup_id);
                    continue;
                }
            
                if(strcmp(vgroup_class,RI_NAME)==0) {
                    ref_num = Vgetid(file_id,ref_num);
                    Vdetach(vgroup_id);
                    continue;
                }
            }

            if(vgroup_name[0] != '\0') {
                if(strcmp(vgroup_name,GR_NAME)==0) {
                    ref_num = Vgetid(file_id,ref_num);
                    Vdetach(vgroup_id);
                    continue;
                }
            }
            if(vgcheck_object(h4toh5id,vgroup_id)==FAIL){
                Vdetach(vgroup_id);
                return FAIL;
            }
            istat = Vdetach(vgroup_id);
            if(istat == FAIL) {
                H4toH5error_set(temph4toh5id,2,
                         "fail to detach vgroup",
                         __FILE__,__LINE__);
                return FAIL;
            }
        }

        ref_num = Vgetid(file_id,ref_num); 
            
    }

#if 0
    free(vgroup_name);
    free(vgroup_class);
#endif

    return SUCCEED;
}

/*-------------------------------------------------------------------------
 * Function:    vgcheck_object
 *
 * Purpose:         check(touch) all SDS and image objects  of this vgroup
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id:                  h4toh5 identifier
        file_id:                        HDF4 file identifier
 *
 *-------------------------------------------------------------------------
 */ 
int vgcheck_object(hid_t h4toh5id,int32 vgroup_id)
{

    int32       obj_tag;/* object tag */
    int32       obj_ref;/* object reference number*/
    int32       num_gobjects; /* number of objects of this vgroup */
    int         i;
    int         temp; /* temporary flag*/
    int         check_sds; /* a flag for checking SDS */
    int         check_image; /* a flag for checking image */
     
    h4toh5id_t* temph4toh5id;  /*  pointer to h4toh5 id struct for 
                passing parameters of error handlings */

    temp = 0;

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

    num_gobjects = Vntagrefs(vgroup_id);
    if(num_gobjects == FAIL) {
        H4toH5error_set(temph4toh5id,2,
                 "fail to obtain number of objects in the vgroup",
                 __FILE__,__LINE__);
        return FAIL;
    }

    for( i = 0;i<num_gobjects;i++) { 
        if(Vgettagref(vgroup_id,i,&obj_tag,&obj_ref)==FAIL) {
            H4toH5error_set(temph4toh5id,2,
         "fail to get tag and reference number of the object",
         __FILE__,__LINE__);
            return FAIL;
        }

        if (Visvg(vgroup_id,obj_ref)) {/* do nothing when it is a vgroup.*/
            continue;
        }
        /* check SDS */
        else if(obj_tag == DFTAG_NDG || obj_tag == DFTAG_SDG){
            check_sds = lookup(h4toh5id,obj_ref,SDS_HASHSIZE,temph4toh5id->sds_hashtab,&temp);
            if(check_sds == 0) {
                if(set_name(h4toh5id,obj_ref,SDS_HASHSIZE,temph4toh5id->sds_hashtab,
                            NULL,-1)==FAIL) {
                    H4toH5error_set(temph4toh5id,4,
                             "cannot set object name properly",
                             __FILE__,__LINE__);
                    return FAIL;
                }
            }
        }

        /* check GR*/
        else if(obj_tag == DFTAG_RIG) {
            check_image = lookup(h4toh5id,obj_ref,IMAGE_HASHSIZE,temph4toh5id->gr_hashtab,&temp);
            if(check_image == 0) {
                if(set_name(h4toh5id,obj_ref,IMAGE_HASHSIZE,temph4toh5id->gr_hashtab,
                            NULL,-1)==FAIL){
                    H4toH5error_set(temph4toh5id,4,
                             "cannot set object name properly",
                             __FILE__,__LINE__);
                    return FAIL;
                }
            }

        }
    }

    return SUCCEED;
}

