/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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 lib API

See HDF4 to HDF5 mapping specification at
(https://support.hdfgroup.org/products/hdf5_tools/h4toh5/) for the default mapping 
from HDF4 object to HDF5 object.

The whole converter library includes 14 files, 

five header files:

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

     h4toh5util.h(constants, utility and internal functions)

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

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

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

nine C files:

     h4toh5util.c(utility and internal functions)
     h4toh5main.c(H4toH5open and h4toh5close functions)
     h4toh5sds.c(h4toh5sds,h4toh5alldimscale and h4toh5onedimscale functions)
     h4toh5image.c(h4toh5image function)
     h4toh5vdata.c(h4toh5vdata function)
     h4toh5vgroup.c(h4toh5basvgroup and h4toh5advgroup functions)
     h4toh5pal.c(h4toh5pal functions)
     h4toh5anno.c(h4toh5anno functions)

2. this file 

Converting an hdf4 palette object into a hdf5 dataset.


Author:  Kent Yang(myang6@hdfgroup.org)
 

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

#include "h4toh5main.h"

/*-------------------------------------------------------------------------
 * Function:    h4toh5pal
 *
 * Purpose:         translate palette into hdf5 dataset
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h4toh5_id: h4toh5 identifier
        pal_id: PALETTE identifier
        h5filename: hdf5 file name
        h5groupname: hdf5 group name
        h5dsetname: hdf5 dataset name
        attr_flag: flag for attribute

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

int H4toH5pal(hid_t h4toh5_id,
                 int32 ri_id,
                 char* h5groupname,
                 char* h5dsetname,
                 char* h5palgroupname,
                 char* h5paldsetname,
                 int attr_flag,
                 int ref_flag) {
    
    int32       ncomp;
    char        image_name[H4H5_MAX_GR_NAME];
    char*       cor_image_name;
    char*       cor_h5dsetname;
    int32       image_dtype;
    int32       dimsizes[2];
    int32       ngrattrs;

    int32       gr_ref;
    int32       pal_id;
    int32       pal_ref;
    int32       pal_type;
    int32       interlace_mode;
    int32       num_entries;
    void*       pal_data;
    size_t  h4memsize;
    size_t  h4size;
    int         check_palname; 
    char*       h5pal_name;
    char*       h5cimage_name = NULL;
    char*       h5crepimage_name;
    char*       ori_h5palname;
    char     refstr[MAXREF_LENGTH];
    int*        check_lookupptr;
    int         temp_palg;
 

    char        palette_label[H4H5_MAX_PAL_NAME];
    char        palette_class[H4H5_MAX_PAL_NAME];
    char        palette_type[H4H5_MAX_PAL_NAME];
    char        palette_colormodel[H4H5_MAX_PAL_NAME];

    hid_t       h5memtype;
    hid_t       h5type;
    hid_t       h5d_sid;
    hid_t       h5_group = -1;
    hid_t       h5dset = -1;
    hid_t       h5paldset;
    hid_t       h5_palgroup;
    hsize_t h5dims[2];
    int         check_pal;
    int         temp;
    int         istat;

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

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

    temp     = 0;
    check_lookupptr = &temp;
    temp_palg = 0;
    gr_ref = GRidtoref(ri_id);

    /* get image information */
    istat = GRgetiminfo(ri_id, image_name, &ncomp, &image_dtype, 
                    NULL, dimsizes, &ngrattrs);

    if(istat == FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain GR general information",
             __FILE__,__LINE__);
        return FAIL;
    }

    /* get palette id */
    pal_id  = GRgetlutid(ri_id,0);
    if(pal_id == FAIL) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain palette id",
             __FILE__,__LINE__);
        return FAIL;
    }

    pal_ref = GRluttoref(pal_id);
    if(pal_ref <0) {
        H4toH5error_set(temph4toh5id,2,"cannot obtain palette reference number",
             __FILE__,__LINE__);
        return FAIL;
    }

    if(pal_ref >0) {     
         
        /* If reference flag is set to 1, 
             obtain h5_group and the absolute path of the image name which 
             the palette is associated with. */

        if(ref_flag == 1) {
            h5_group        =  get_h5groupid(h5groupname,h4toh5_id,attr_flag);
            if(h5_group < 0) {
                H4toH5error_set(temph4toh5id,5,"cannot obtain HDF5 group id from get_h5groupid",
                                               __FILE__,__LINE__);
                return FAIL;
            }
        
            if(h5dsetname == NULL) {
                /* change format of reference number. */
                if(conv_int_str(h4toh5_id,(uint32)gr_ref,refstr)== FAIL) {
                    H4toH5error_set(temph4toh5id,5,"cannot convert reference number into string type",
                         __FILE__,__LINE__);
                    return FAIL;
                }
            /*  generating two names. 
     1. make up name based on HDF4_IMAGE,h5groupname,gr_ref.
     call this name h5repimage_name
     2. using lookup_name to check whether this name is stored already.
     3. If yes, use this name as the h5datasetname.
     4. no, obtain name based on group name + image name.
            */
                h5crepimage_name = make_objname_no(h4toh5_id,refstr,h5groupname,
                                     HDF4_IMAGE);
                if(lookup_name(h4toh5_id,h5crepimage_name,IMAGE_HASHSIZE,
                                 temph4toh5id->name_hashtab)==1){
                    h5cimage_name = malloc(strlen(h5crepimage_name)+1);
                    if(h5cimage_name == NULL) {
                        H4toH5error_set(temph4toh5id,1,"cannot allocate memory for image name",
                                 __FILE__,__LINE__);
                        return FAIL;
                    }
                    strncpy(h5cimage_name,h5crepimage_name,strlen(h5crepimage_name));
                }
            
                else {
                     cor_image_name = correct_name(h4toh5_id,image_name);
                    if(cor_image_name == NULL) {
                        H4toH5error_set(temph4toh5id,4,
                     "cannot obtain corrected image name",__FILE__,__LINE__);
                        return FAIL;
                    }
                    h5cimage_name = make_objname_yes(h4toh5_id,cor_image_name,h5groupname);
                    free(cor_image_name);
                }
                if(h5crepimage_name != NULL)
                        free(h5crepimage_name);
            }
            else {
                cor_h5dsetname = correct_name(h4toh5_id,h5dsetname);
                if(cor_h5dsetname == NULL) {
                    H4toH5error_set(temph4toh5id,4,
                 "cannot obtain corrected HDF5 dataset name",__FILE__,__LINE__);
                    return FAIL;
                }
                h5cimage_name = make_objname_yes(h4toh5_id,cor_h5dsetname,h5groupname);
                free(cor_h5dsetname);
                if(lookup_name(h4toh5_id,h5cimage_name,IMAGE_HASHSIZE,
                             temph4toh5id->name_hashtab)==0){
                /*printf("this object name has not been used or set by converter");
                printf(" API, the converting results may be unexpected.\n");*/
                }
            }
    
            h5dset = H5DOPEN(h5_group,h5cimage_name); 
            if (h5dset < 0) {                               
                H4toH5error_set(temph4toh5id,3,"cannot create HDF5 dataset",
                                                __FILE__,__LINE__);
                free(h5cimage_name);
                H5Gclose(h5_group);
                return FAIL;    
            }
            
        }

        /* obtain HDF5 palette group name */

        if(h5palgroupname == NULL){
            h5palgroupname = malloc(strlen(HDF4_PALG)+1);
            if(h5palgroupname == NULL) {
                H4toH5error_set(temph4toh5id,1,
                         "No enough memory to be allocated for palette group",
                         __FILE__,__LINE__);
                if(ref_flag == 1) {
                    H5Dclose(h5dset);
                    free(h5cimage_name);
                    H5Gclose(h5_group);
                }
                return FAIL;
            }
            strcpy(h5palgroupname,HDF4_PALG);
            temp_palg = 1;
        }
        
        
        /* obtain hdf5 palette group id and the absolute path name of hdf5 palette name. */

        h5_palgroup =  get_h5groupid(h5palgroupname,h4toh5_id,attr_flag);
        if(h5_palgroup < 0) {
            H4toH5error_set(temph4toh5id,5,"cannot obtain HDF5 group id",
             __FILE__,__LINE__);
            if(ref_flag == 1){
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            if(temp_palg==1)
                free(h5palgroupname);
            return FAIL;
        }

        /* check whether this palette has been looked up already. */
        check_pal = lookup(h4toh5_id,pal_ref,PAL_HASHSIZE,
                     temph4toh5id->pal_hashtab,&temp);

        if(h5paldsetname == NULL){
            
            /* 
             1) Assume the user will not use HDF4_PALETTE_REF as their own 
                    SDS name. 
             2) Check whether this PALETTE was looked up or not. If this PALETTE
                    has been looked up, it must be assigned a name. 
                    lookup_name is used to make sure the obtained name is not used 
                    before. 
                    */
            h5pal_name = get_h5datasetname(h4toh5_id,h5palgroupname,NULL,
                             (uint16)pal_ref,HDF4_PALETTE,
                             OBJECT_HASHSIZE,check_lookupptr);
            
            if(h5pal_name == NULL) {

                H4toH5error_set(temph4toh5id,4,"the palette name cannot be obtained",
                    __FILE__,__LINE__);
                if(ref_flag ==1) {
                   H5Dclose(h5dset);
                   H5Gclose(h5_group);
                   free(h5cimage_name);
                }
                H5Gclose(h5_palgroup);
                free(h5pal_name);
                if(temp_palg==1)
                   free(h5palgroupname);
                return FAIL;
            }
            if(lookup_name(h4toh5_id,h5pal_name,OBJECT_HASHSIZE,
                 temph4toh5id->name_hashtab)==1) {
                H4toH5error_set(temph4toh5id,4,"the palette name has been used",
                         __FILE__,__LINE__);
                if(ref_flag ==1) {
                    H5Dclose(h5dset);
                    H5Gclose(h5_group);
                    free(h5cimage_name);
                }
                H5Gclose(h5_palgroup);
                free(h5pal_name);
                if(temp_palg==1)
                    free(h5palgroupname);
                return FAIL;
            }
        }
        else {
            h5pal_name = get_h5datasetname(h4toh5_id,h5palgroupname,h5paldsetname,
                         (uint16)pal_ref,HDF4_PALETTE,OBJECT_HASHSIZE,
                         check_lookupptr);
            if(h5pal_name == NULL) {

                H4toH5error_set(temph4toh5id,4,"the palette name cannot be obtained",
                     __FILE__,__LINE__);
                if(ref_flag ==1) {
                    H5Dclose(h5dset);
                    H5Gclose(h5_group);
                    free(h5cimage_name);
                }
                H5Gclose(h5_palgroup);
                free(h5pal_name);
                if(temp_palg==1)
                    free(h5palgroupname);
                return FAIL;
            }
            if(*check_lookupptr == 1) {/* the user-input palette name is used.*/
                H4toH5error_set(temph4toh5id,4,"this HDF5 palette name has been used",
                                                __FILE__,__LINE__);
                if(ref_flag == 1) {
                    H5Dclose(h5dset);
                    H5Gclose(h5_group);
                    free(h5cimage_name);
                }
                H5Gclose(h5_palgroup);
                free(h5pal_name);
                if(temp_palg==1)
                    free(h5palgroupname);
                return FAIL;
            }
        }

        /* update hdf5 dataset table. */
        if(lookup_updatename(h4toh5_id,h5pal_name,OBJECT_HASHSIZE,
             temph4toh5id->name_hashtab)==-1) {
            H4toH5error_set(temph4toh5id,4,"this palette name has been used",
             __FILE__,__LINE__);
            if(ref_flag == 1) {
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            H5Gclose(h5_palgroup);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
            return FAIL;
        }

        /* if check_pal equals to 1, this palette has already been 
             converted into an hdf5 dataset, just obtain the palette 
             name and return SUCCEED.
             if check_pal equals to 0, we will do the converting. */

        if(check_pal == 0) {
            if(set_name(h4toh5_id,pal_ref,PAL_HASHSIZE,temph4toh5id->pal_hashtab,
            h5pal_name,-1)==FAIL) {
                H4toH5error_set(temph4toh5id,4,"cannot set HDF5 object name",
                          __FILE__,__LINE__);
                if(ref_flag == 1) {
                      H5Dclose(h5dset);
                      H5Gclose(h5_group);
                      free(h5cimage_name);
                }
                H5Gclose(h5_palgroup);
                free(h5pal_name);
                if(temp_palg==1)
                     free(h5palgroupname);
                return FAIL;
            }
        }
        else {

            /* the touched palette name will be grabed. the input h5palsetname and 
     h5palgroupname will be ignored. */
                 
            ori_h5palname = get_name(h4toh5_id,pal_ref,PAL_HASHSIZE,
                         temph4toh5id->pal_hashtab,
                         &check_palname);
                         
            if (ori_h5palname == NULL && check_palname == 0 ) {                 
                H4toH5error_set(temph4toh5id,4,"cannot find HDF5 palette name",
                         __FILE__,__LINE__);
                if(ref_flag == 1) { 
                    H5Dclose(h5dset);
                    H5Gclose(h5_group);
                    free(h5cimage_name);
                }
                H5Gclose(h5_palgroup);
                free(ori_h5palname);
                free(h5pal_name);
                if(temp_palg==1)
                    free(h5palgroupname);
                return FAIL;                                        
            }                                       
                                                
            if (ori_h5palname == NULL && check_palname == -1 ) {                 
                H4toH5error_set(temph4toh5id,4,"palette name is not defined",
                         __FILE__,__LINE__);
                if(ref_flag == 1) { 
                    H5Dclose(h5dset);
                    H5Gclose(h5_group);
                    free(h5cimage_name);
                }
                H5Gclose(h5_palgroup);
                free(ori_h5palname);
                free(h5pal_name); 
                if(temp_palg==1)
                    free(h5palgroupname);
                return FAIL;                                        
            }   
        
            if(H5Glink(h5_palgroup,H5G_LINK_HARD,ori_h5palname,h5pal_name) <0) {
                H4toH5error_set(temph4toh5id,3,"cannot create Hard Link",
                         __FILE__,__LINE__);
                if(ref_flag == 1) { 
                    H5Dclose(h5dset);
                    H5Gclose(h5_group);
                    free(h5cimage_name);
                }
                H5Gclose(h5_palgroup);
                free(ori_h5palname);
                free(h5pal_name);
                if(temp_palg==1)
                    free(h5palgroupname);
                return FAIL;
            }

            if(ref_flag == 0) {
                /*** no object reference and hdf5 dataset name will be returned. ***/
                
                H5Gclose(h5_palgroup);
                free(ori_h5palname);
                free(h5pal_name);
                if(temp_palg==1)
                    free(h5palgroupname);
                return SUCCEED;
            }
            create_pal_objref(h4toh5_id,h5dset,h5_palgroup,h5pal_name);
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            H5Gclose(h5_palgroup);
            free(ori_h5palname);
            free(h5cimage_name);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
            return SUCCEED;
        }

        if(GRgetlutinfo(pal_id,&ncomp,&pal_type,&interlace_mode,
                &num_entries)==FAIL) {
            H4toH5error_set(temph4toh5id,2,"cannot obtain palette information",
             __FILE__,__LINE__);
            if(ref_flag == 1){
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            H5Gclose(h5_palgroup);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
            return FAIL;
        }

        if(h4type_to_h5type(h4toh5_id,pal_type,&h5memtype,
            &h4memsize,&h4size,&h5type)== FAIL) {
            H4toH5error_set(temph4toh5id,5,"cannot convert data type",
             __FILE__,__LINE__);
            if(ref_flag == 1) {
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            H5Gclose(h5_palgroup);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
            H5Gclose(h5_group);
            return FAIL;
        }
    
        /* according to mapping document, data type for palette will always be
             uint8. */

        if (h5type == H5T_STRING) {
            if(h5string_to_int(h4toh5_id,pal_type,&h5memtype,h4memsize,
             &h5type)==FAIL) {
                H4toH5error_set(temph4toh5id,5,"cannot convert HDF5 string(char) to integer",
                         __FILE__,__LINE__);
                if(ref_flag == 1) {
                    H5Dclose(h5dset);
                    H5Gclose(h5_group);
                    free(h5cimage_name);
                }
                H5Gclose(h5_palgroup);
                free(h5pal_name);
                if(temp_palg==1)
                    free(h5palgroupname);
                return FAIL;
            }
        }
        
        h5dims[0] = num_entries;
        h5dims[1] = ncomp;
         
        pal_data = malloc(h4memsize*ncomp*num_entries);
        
        if (pal_data == NULL) {
            H4toH5error_set(temph4toh5id,1,"No enough memory for palette data",
                     __FILE__,__LINE__);
            if(ref_flag == 1) {
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            H5Gclose(h5_palgroup);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
            return FAIL;
        }

        if (GRreadlut(pal_id,(VOIDP)pal_data)==FAIL) {
            H4toH5error_set(temph4toh5id,2,"cannot read palette data",
                     __FILE__,__LINE__);
            if(ref_flag == 1) {
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            free(pal_data);
            H5Gclose(h5_palgroup);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
            return FAIL;
        }

        /** PART II. converting hdf4 into hdf5. **/

        h5d_sid = H5Screate_simple(2,h5dims,NULL);

        if (h5d_sid <0) {
            H4toH5error_set(temph4toh5id,3,"cannot create HDF5 dataset space id",
                                     __FILE__,__LINE__);
            free(pal_data);
            if(ref_flag == 1) {
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            H5Gclose(h5_palgroup);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
                    return FAIL;
        }
 
        h5paldset = H5DCREATE(h5_palgroup,h5pal_name,h5type,h5d_sid,H5P_DEFAULT);
        if (h5paldset < 0) {
            H4toH5error_set(temph4toh5id,3,"cannot create HDF5 dataset id",
                    __FILE__,__LINE__);
            free(pal_data);
            if(ref_flag == 1) {
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            H5Sclose(h5d_sid);
            H5Gclose(h5_palgroup);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
            return FAIL;
        }

        if (H5Dwrite(h5paldset,h5memtype,h5d_sid,h5d_sid,H5P_DEFAULT,
                   (void *)pal_data)<0) {
            H4toH5error_set(temph4toh5id,3,"cannot write HDF5 data",
                    __FILE__,__LINE__);
            free(pal_data);
            H5Sclose(h5d_sid);
            H5Dclose(h5paldset);
            if(ref_flag == 1) {
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            H5Gclose(h5_palgroup);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
            return FAIL;
        }
        free(pal_data);
 
        if(is_valid_attr_flag(attr_flag)==0) {
            H4toH5error_set(temph4toh5id,5,"attribute flag is set wrong",
                     __FILE__,__LINE__);
            H5Sclose(h5d_sid);
            H5Dclose(h5paldset);
            if(ref_flag == 1) {
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            H5Gclose(h5_palgroup);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
            return FAIL;

        }

        if(ref_flag <0 || ref_flag > 1) {
            H4toH5error_set(temph4toh5id,5,"reference flag is set wrong",
                     __FILE__,__LINE__);
            if(ref_flag == 1) {
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            H5Sclose(h5d_sid);
            H5Dclose(h5paldset);
            H5Gclose(h5_palgroup);
            if(temp_palg==1)
                free(h5palgroupname);
            free(h5pal_name);
            return FAIL;

        }

        strcpy(palette_class,PALETTE);
        strcpy(palette_type,PAL_TYPE);
        strcpy(palette_colormodel,HDF5_RGB);

                /*the following attributes are necessary for palette handling. */

        if(h4_transpredattrs(h4toh5_id,h5paldset,HDF4_PALETTE_VERSION_ATTR,
             HDF5PAL_SPE_VERSION)==FAIL){
            H4toH5error_set(temph4toh5id,5,
                     "unable to generate HDF4_PALETTE_CLASS attribute",
                     __FILE__,__LINE__);
            if(ref_flag == 1) {
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            H5Sclose(h5d_sid);
            H5Dclose(h5paldset);
            H5Gclose(h5_palgroup);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
            return FAIL;
        }

        if(h4_transpredattrs(h4toh5_id,h5paldset,HDF4_PALETTE_CLASS,
                 palette_class)==FAIL){
            H4toH5error_set(temph4toh5id,5,
                     "unable to generate HDF4_PALETTE_CLASS attribute",
                     __FILE__,__LINE__);
            if(ref_flag == 1) {
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            H5Sclose(h5d_sid);
            H5Dclose(h5paldset);
            H5Gclose(h5_palgroup);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
            return FAIL;
        }

        if(h4_transpredattrs(h4toh5_id,h5paldset,HDF4_PALETTE_TYPE,
                 palette_type)==FAIL){
            H4toH5error_set(temph4toh5id,5,
             "unable to convert HDF4_PALETTE_TYPE attribute",
             __FILE__,__LINE__);
            if(ref_flag == 1) {
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            H5Sclose(h5d_sid);
            H5Dclose(h5paldset);
            H5Gclose(h5_palgroup);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
            return FAIL;
        }
        if(h4_transpredattrs(h4toh5_id,h5paldset,PAL_COLORMODEL,palette_colormodel)==FAIL){
            H4toH5error_set(temph4toh5id,5,
             "unable to convert HDF4 palette color model attribute",
             __FILE__,__LINE__);
            if(ref_flag == 1) {
                H5Dclose(h5dset);
                H5Gclose(h5_group);
                free(h5cimage_name);
            }
            H5Sclose(h5d_sid);
            H5Dclose(h5paldset);
            H5Gclose(h5_palgroup);
            free(h5pal_name);
            if(temp_palg==1)
                free(h5palgroupname);
            return FAIL;
        } 
        if(is_valid_attr_flag(attr_flag) && attr_flag != H425_NOATTRS) {

            strcpy(palette_label,PALABEL);
         
            /* convert palette annotation into attribute of palette dataset.
     Since there are no routines to find the exact tag of palette object,
     we will check three possible object tags of palette objects, that is:
     DFTAG_LUT. If the object tag of palette object is 
     falling out of this scope, we will not convert annotations into
     hdf5 attributes; 
     it is user's responsibility to make sure that object tags
     for palette objects are DFTAG_LUT.*/
            
            if(H4toH5anno_obj_all_labels_new(h4toh5_id,h5palgroupname,h5pal_name,(uint16)pal_ref,
                DFTAG_LUT,attr_flag)==FAIL) {
                H4toH5error_set(temph4toh5id,5,
                         "palette annotation object label conversion is wrong",
                         __FILE__,__LINE__);
                if(ref_flag == 1) {
                    H5Dclose(h5dset);
                    H5Gclose(h5_group);
                    free(h5cimage_name);
                }
                H5Sclose(h5d_sid);
                H5Dclose(h5paldset);
                H5Gclose(h5_palgroup);
                if(temp_palg==1)
                    free(h5palgroupname);
                free(h5pal_name);
                return FAIL;
            }

            if(H4toH5anno_obj_all_descs_new(h4toh5_id,h5palgroupname,h5pal_name,(uint16)pal_ref,
                DFTAG_LUT,attr_flag)==FAIL){
                H4toH5error_set(temph4toh5id,5,
                         "palette annotation object description conversion is wrong",
                         __FILE__,__LINE__);
                if(ref_flag == 1) {
                    H5Dclose(h5dset);
                    H5Gclose(h5_group);
                    free(h5cimage_name);
                }
                H5Sclose(h5d_sid);
                H5Dclose(h5paldset);
                H5Gclose(h5_palgroup);
                if(temp_palg==1)
                    free(h5palgroupname);
                free(h5pal_name);
                return FAIL;
            }

            if(attr_flag == H425_OSPEC_ALLATTRS || attr_flag == H425_ALLATTRS){
                if(h4_transpredattrs(h4toh5_id,h5paldset,HDF4_OBJECT_TYPE,
                 palette_label)==FAIL) {
                    H4toH5error_set(temph4toh5id,5,
                       "unable to generate OBJECT TYPE attribute",
                       __FILE__,__LINE__);
                    if(ref_flag == 1) {
                        H5Dclose(h5dset);
                        H5Gclose(h5_group);
                        free(h5cimage_name);
                    }
                    H5Sclose(h5d_sid);
                    H5Dclose(h5paldset);
                    H5Gclose(h5_palgroup);
                    if(temp_palg==1)
                        free(h5palgroupname);
                    free(h5pal_name);
                    return FAIL;
                }

            
                if(h4_transnumattr(h4toh5_id,h5paldset,HDF4_REF_NUM,(uint16)pal_ref)==FAIL) {
                    H4toH5error_set(temph4toh5id,5,
                         "unable to generate HDF4_REF_NUM attribute",__FILE__,__LINE__);
                    if(ref_flag == 1) {
                        H5Dclose(h5dset);
                        H5Gclose(h5_group);
                        free(h5cimage_name);
                    }
                    H5Sclose(h5d_sid);
                    H5Dclose(h5paldset);
                    H5Gclose(h5_palgroup);
                    free(h5pal_name);
                    if(temp_palg==1)
                        free(h5palgroupname);
                    return FAIL;
                }
            }
        }
        if(ref_flag ==1) {
            /* h5palgroupname = get_groupname(h5pal_name);
     h5_palgroup = get_h5groupid(h5palgroupname,h4toh5_id);*/
 
            if(create_pal_objref(h4toh5_id,h5dset,h5_palgroup,h5pal_name)== FAIL){
                H4toH5error_set(temph4toh5id,5,
                 "unable to create object reference to the palette",
                 __FILE__,__LINE__);
                H5Sclose(h5d_sid);
                H5Dclose(h5paldset);
                H5Gclose(h5_palgroup);
                free(h5cimage_name);
                free(h5pal_name);
                if(temp_palg==1)
                    free(h5palgroupname);
                return FAIL;
            }

            if(store_palattrname(h4toh5_id,h5pal_name,h5dset)==FAIL){
                H4toH5error_set(temph4toh5id,5,
                 "unable to create attribute name to the palette",
                 __FILE__,__LINE__);
                H5Sclose(h5d_sid);
                H5Dclose(h5paldset);
                H5Gclose(h5_palgroup);
                free(h5cimage_name);
                free(h5pal_name);
                if(temp_palg==1)
                    free(h5palgroupname);
                return FAIL;
            }
        }
    
        H5Sclose(h5d_sid);
        H5Dclose(h5paldset);
        H5Gclose(h5_palgroup);
        if(ref_flag ==1) {
            H5Dclose(h5dset);
            H5Gclose(h5_group);
            free(h5cimage_name);
        }
        free(h5pal_name);
        if(temp_palg==1)
            free(h5palgroupname);
    }
    return SUCCEED;
}
    
/*----------------------------------------------------------------
 * Function:    create_pal_objref
 *
 * Purpose:         create object reference for palette
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h5dset: hdf5 dataset
        h5_palgroup: hdf5 palette group
        h5pal_name: hdf5 palette name

     Out:                   
 *------------------------------------------------------------------
 */ 

int create_pal_objref(hid_t h4toh5_id,
                    hid_t h5dset,
                    hid_t h5_palgroup,
                    char *h5pal_name){

    hobj_ref_t pal_refdat;
    hsize_t      pal_refDims[1];
    hid_t            pal_refSpace;
    hid_t            pal_refType;
    hid_t            attribID;
    herr_t       ret;
    h4toh5id_t* temph4toh5id;

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

    pal_refDims[0] = 1;
    pal_refSpace     = H5Screate_simple(1,pal_refDims,NULL);

    if(pal_refSpace < 0) {
        H4toH5error_set(temph4toh5id,3,
             "unable to obtain HDF5 reference space id",
             __FILE__,__LINE__);
        return FAIL;
    }

    pal_refType      = H5Tcopy(H5T_STD_REF_OBJ);
    if(pal_refType < 0) {
        H4toH5error_set(temph4toh5id,3,
             "unable to create HDF5 object reference type",
             __FILE__,__LINE__);
        H5Sclose(pal_refSpace);
        return FAIL;
    }

    ret                      = H5Rcreate(&pal_refdat,h5_palgroup,h5pal_name,
                     H5R_OBJECT,-1);
    if(ret < 0) {
        H4toH5error_set(temph4toh5id,3,
             "unable to create HDF5 reference id",
             __FILE__,__LINE__);
        H5Sclose(pal_refSpace);
        H5Tclose(pal_refType);
        return FAIL;
    }

    attribID             = H5ACREATE(h5dset,PALETTE,pal_refType,pal_refSpace,
                     H5P_DEFAULT);

    if(attribID < 0) {
        H4toH5error_set(temph4toh5id,3,
             "unable to obtain attribute ID",
             __FILE__,__LINE__);
        H5Sclose(pal_refSpace);
        H5Tclose(pal_refType);
        return FAIL;
    }

    ret                      = H5Awrite(attribID,pal_refType,(void *)&pal_refdat);

            
    H5Sclose(pal_refSpace);
    if(H5Tclose(pal_refType)<0) {
        H4toH5error_set(temph4toh5id,3,
             "unable to write HDF5 attribute data",
             __FILE__,__LINE__);
        H5Aclose(attribID);
    }       
    H5Aclose(attribID);
    return SUCCEED;
}

/*----------------------------------------------------------------
 * Function:    store_palattrname
 *
 * Purpose:         store HDF5 palette name as the attribute of the
                                image
 *                          
 * Return:  FAIL if failed, SUCCEED if successful.
 *
 * In :                 
        h5toh5id: h4toh5 id
        h5_dset: hdf5 data set
        h5pal_name: hdf5 palette name

     Out:                   
 *------------------------------------------------------------------
 */ 

int store_palattrname(hid_t h4toh5id,
             char* h5pal_name,
             hid_t h5_dset) {

    hid_t       h5str_palntype;
    hid_t       h5pal_nameaid;
    hid_t       h5pal_namesid;
    hsize_t h5pal_dims[1];
    hid_t       ret;
    
    h4toh5id_t *temph4toh5id;

    temph4toh5id = H4TOH5I_object(h4toh5id);

    h5pal_dims[0]        = 1;

    /*h5pal_namesid      = H5Screate_simple(1,h5pal_dims,NULL);*/   
    h5pal_namesid        = H5Screate(H5S_SCALAR);   

    if(h5pal_namesid <0) {
            H4toH5error_set(temph4toh5id,3,
         "unable to create palette space",
         __FILE__,__LINE__);
            return FAIL;
    }

    /*h5str_palntype     = mkstr(h4toh5id,H4H5_MAX_DIM_NAME,H5T_STR_NULLTERM);*/    
    h5str_palntype = H5Tcopy(H5T_C_S1);
    H5Tset_size(h5str_palntype,H5T_VARIABLE);

    if(h5str_palntype < 0) {
            H5Sclose(h5pal_namesid);
            H4toH5error_set(temph4toh5id,3,
         "unable to make HDF5 string data type",
         __FILE__,__LINE__);
            return FAIL;
    }
    h5pal_nameaid        = H5ACREATE(h5_dset,HDF4_PALETTE_LIST,h5str_palntype,
                 h5pal_namesid,H5P_DEFAULT);                    

    if(h5pal_nameaid <0) {
        H5Sclose(h5pal_namesid);
        H4toH5error_set(temph4toh5id,3,
         "unable to create HDF5 palette attributes",
         __FILE__,__LINE__);
        return FAIL;
    }

    ret = H5Awrite(h5pal_nameaid,h5str_palntype,&h5pal_name);

    if(ret < 0) {
        H5Sclose(h5pal_namesid);
        H5Aclose(h5pal_nameaid);
        H4toH5error_set(temph4toh5id,3,
         "unable to write HDF5 palette name attributes",
         __FILE__,__LINE__);
        return FAIL;
    }
        
    H5Tclose(h5str_palntype);
    H5Sclose(h5pal_namesid);
    H5Aclose(h5pal_nameaid);
    return SUCCEED;
}
    




