/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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 full H4H5TOOLS copyright notice can    *
 * also be found at https://www.hdfgroup.org/licenses.  If you do not have   *
 * access to either file, you may request a copy from help@hdfgroup.org.     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

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

  Description: 

1. H4toH5 converter library 

See HDF4 to HDF5 mapping specification at
(http://www.hdfgroup.org/HDF5/papers/h4toh5) for the default mapping 
from HDF4 object to HDF5 object.
 
The whole converter library includes 13 files:
SOURCES = H4TOH5I.c h4toh5anno.c h4toh5pal.c h4toh5sds.c h4toh5util.c 
          h4toh5vdata.c h4toh5vgroup.c h4toh5image.c h4toh5main.c h4toh5eos.c
                                                                                
HEADERS = h4toh5.h H4TOH5api_adpt.h h4toh5vector.h

2. this file 

Including declarations of constant and utility subroutines

Author:  Kent Yang(myang6@hdfgroup.org)
 

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


#ifndef UTILITY_H
#define UTILITY_H

#include "hdf5_hl.h"
#include "hdf5.h"
#include "hdf.h"
#include "mfhdf.h"
#include "H4TOH5Ipublic.h"
#include "H4TOH5Iprivate.h"
#include "h4toh5.h"
#include <string.h>

/**********************************************/
/*************** section I *******************/
/*This section  describes reserved
name and global constants  used in h4-h5 
converter library.*/
/*********************************************/

/* 0. if "/" is found in hdf4 object name, we will use another
   character "_" to replace it, since "/" is a reserved symbol 
   in HDF5. */

#define ORI_SLASH '/'
#define CHA_SLASH '_'

/* 1. character string used for default attribute name. */

#define ATTR "ATTR"

/* 2. Predefined HDF5 Attribute name for HDF4 file */

#define HDF4_OBJECT_NAME    "HDF4_OBJECT_NAME"
#define HDF4_OBJECT_TYPE    "HDF4_OBJECT_TYPE"
#define HDF4_REF_NUM        "HDF4_REF_NUM"
#define HDF4_VGROUP_CLASS   "HDF4_VGROUP_CLASS"
#define HDF4_IMAGE_CLASS    "CLASS"
#define HDF4_IMAGE_SUBCLASS "IMAGE_SUBCLASS"
#define HDF4_PALETTE_CLASS  "CLASS"
#define HDF4_PALETTE_TYPE   "PAL_TYPE"
#define PAL_TYPE            "STANDARD8"


/* 3. Reserved name for HDF5 object  when in name clashing. */

#define HDF4_VGROUP         "HDF4_VGROUP"
#define HDF4_PALETTE        "HDF4_PALETTE"
#define HDF4_SDS            "HDF4_SDS"
#define HDF4_VDATA          "HDF4_VDATA"
#define HDF4_IMAGE          "HDF4_IMAGE"
#ifdef HAVE_LIBHDFEOS
#define HDFEOS2_GRID		"HDFEOS2_GRID"
#define HDFEOS2_GRID_FIELD	"HDFEOS2_GRID_FIELD"
#define HDFEOS2_SWATH		"HDFEOS2_SWATH"
#define HDFEOS2_POINT		"HDFEOS2_POINT"
#endif

/* 4. Global palette and dimension_list name. */

/*#define HDF4_IMAGE_PALETTE  "HDF4_IMAGE_PALETTE"  

not necessary since image will use PALETTE as the object reference list name, keep it here for future refrence.  */
#define HDF4_DIMENSION_NAMELIST "DIMENSION_NAMELIST"
#define HDF4_PALETTE_LIST   "PALETTE_NAMELIST"
#define PALETTE             "PALETTE"
#define DIMSCALE            "DIMENSIONLIST"

#define HDF5_DIMENSION_LIST		"DIMENSION_LIST"
#define HDF5_DIMENSION_LABELLIST	"DIMENSION_LABELLIST"
#define HDF5_REFERENCE_LIST		"REFERENCE_LIST"
#define HDF5_DIMENSION_SCALE_CLASS	"CLASS"
#define HDF5_DIMENSION_SCALE_NAME	"NAME"

/* 5. Define sds and image file attributes. 
   These file attributes will be put under root group. */

#define GLOSDS "GLOSDS"
#define GLOIMAGE  "GLOIMAGE"

/* 6. define HDF object label.*/
#define SDSLABEL    "SDS"
#define VDATALABEL  "Vdata"
#define VGROUPLABEL "Vgroup"
#define GRLABEL     "GR"
#define RAST8LABEL  "raster8"
#define RAST24LABEL "raster24"
#define PALABEL     "palette"

/* 7. define image and palette attribute names required by
   image spec(http://www.hdfgroup.org/HDF5/doc/ADGuide/ImageSpec.html) */
#define IM_CLASS            "IMAGE"
#define INTERLACE_MODE      "INTERLACE_MODE"
#define PIXEL_INTERLACE     "INTERLACE_PIXEL"
#define LINE_INTERLACE      "INTERLACE_LINE"
#define PLANE_INTERLACE     "INTERLACE_PLANE"
#define HDF4_IMAGE_INDEXED  "IMAGE_INDEXED"
#define HDF4_IMAGE_TRUECOLOR "IMAGE_TRUECOLOR"
#define PAL_COLORMODEL      "PAL_COLORMODEL"
#define HDF5_RGB            "RGB"

/* 7.5: define Vdata attribute names required by
   HDF5 table spec(http://www.hdfgroup.org/HDF5/hdf5_hl/doc/RM_hdf5tb_spec.html */
#define HDF4_VDATA_CLASS "CLASS"
#define VDATA_CLASS "TABLE"
#define HDF5_TABLE_TITLE "TITLE"

/* 8. reserved group name for HDF4 dimensional scale and palette. */
#define HDF4_DIMG           "/HDF4_DIMGROUP"
#define HDF4_PALG           "/HDF4_PALGROUP"
#ifdef HAVE_LIBHDFEOS
#define HDFEOS2_DIMG		"/HDFEOS2_DIMGROUP"
#endif

/* 9. reserved name for HDF4 file label,file description, object label, object description. */
#define HDF4_FILE_LABEL     "HDF4_FILE_LABEL"
#define HDF4_FILE_DESC      "HDF4_FILE_DESCRIPTION"
#define HDF4_OBJECT_LABEL   "HDF4_OBJECT_LABEL"
#define HDF4_OBJECT_DESC    "HDF4_OBJECT_DESCRIPTION"
#define HDF4_SDS_LABEL      "HDF4_SDS_LABEL"
#define HDF4_SDS_DESC       "HDF4_SDS_DESC"
#define HDF4_IMAGE_LABEL    "HDF4_IMAGE_LABEL"
#define HDF4_IMAGE_DESC     "HDF4_IMAGE_DESC"
#define HDF4_VDATA_LABEL    "HDF4_VDATA_LABEL"
#define HDF4_VDATA_DESC     "HDF4_VDATA_DESC"
#define HDF4_VGROUP_LABEL   "HDF4_VGROUP_LABEL"
#define HDF4_VGROUP_DESC    "HDF4_VGROUP_DESC"
#define HDF4_PAL_LABEL      "HDF4_PAL_LABEL"
#define HDF4_PAL_DESC       "HDF4_PAL_DESC"


/*10. palette and dimensional scale hash size and the
  maximum length of object reference number in string format.
  Global variables of Vgroup, Vdata, SDS, image and total number of
  the object, number of global SDS attributes and GR attributes.*/

#define PAL_HASHSIZE     64
#define DIM_HASHSIZE     64
#define VG_HASHSIZE      64
#define VD_HASHSIZE      64
#define SDS_HASHSIZE     128
#define IMAGE_HASHSIZE   128
#define OBJECT_HASHSIZE  128
#define NAME_HASHSIZE    64

/* These constants are added to support the use of HDF5 dimension scale APIs. 
   DIMPURE_HASHSIZE is the size of a hash table to handle the user-defined SDS dimensions 
   that don't have dimension scales.

   DIMSCALE_HASHSIZE is the size of a hash table to handle the user-defined SDS dimensions
   that have dimension scales.
*/ 
#define DIMPURE_HASHSIZE 8
#define DIMSCALE_HASHSIZE 8

/* This should be enough to hold a textual representation of reference number.
 * If the reference number is of very long type like 2^128 in the future,
 * this will not be safe */
#define MAXREF_LENGTH    32


/*12. miscelleous defination. */
/*considering the string size of HDF4_DIMGROUP. we add this into 276*/
#define H4H5_MAX_DIM_NAME   276
#define H4H5_MAX_PAL_NAME   32
#define H4H5_GZIP_COMLEVEL 9
#ifdef  MAX_VAR_DIMS
#define H4H5_MAX_VAR_DIMS MAX_VAR_DIMS
#else
#define H4H5_MAX_VAR_DIMS H4_MAX_VAR_DIMS
#endif
#ifdef  MAX_NC_NAME
#define H4H5_MAX_NC_NAME MAX_NC_NAME
#else 
#define H4H5_MAX_NC_NAME H4_MAX_NC_NAME
#endif
#ifdef  MAX_GR_NAME
#define H4H5_MAX_GR_NAME MAX_GR_NAME
#else
#define H4H5_MAX_GR_NAME H4_MAX_GR_NAME
#endif /* The reason for using #ifdef #endif block is because HDF4 added a
H4 for MAX_NC_NAME and MAX_GR_NAME in new version. We handled this way
to hopefully make h4h5tools work with previous version of HDF4. 9/27/07 */


/*adding a specified vdata class name to deal with the situation 
when independent vdata is HDF chunking table _HDF_CHK_TBL_CLASS, 
if it becomes public constant for hdf lib, this constant can be 
released.*/
#define _HDF_CHK_TBL_CLASS "_HDF_CHK_TBL_"

/* fake sds dimension name*/
#define fakeDim  "fakeDim"

/* for h4toh5 library API. */
/* define error length and the length of the string to store 
   version number. */
#define ERR_LEN    32
#define VER_LEN    32

/* specification version number. */
/* For this release, we opt LIBH4TOH5_VERSION out. In the future release, we may use other way to record library version.  */
/* #define LIBH4TOH5_VERSION "LIBH4TOH51.2" */
#define HDF4_VDATA_VERSION_ATTR "VERSION"
#define HDF5TABLE_SPE_VERSION "1.0"
#define HDF4_IMAGE_VERSION_ATTR "IMAGE_VERSION"
#define HDF5IMAGE_SPE_VERSION "1.2"
#define HDF4_PALETTE_VERSION_ATTR "PAL_VERSION"
#define HDF5PAL_SPE_VERSION "1.2"
extern char str_version[VER_LEN];

/* If an SDS with an unlimited dimension has no elements, "h4toh5" should calculate
 * a good chunk size for that unlimited dimension. The following macro defines how
 * many elements will be put one chunk. If this number is too big, the file size can
 * be bigger. If this number is too small, this file may suffer from bad performance.
 */
/*512 is too small, change to 2048 */
/*#define H4H5_DEFAULT_NUMELEM_IN_CHUNK  512 */
#define H4H5_DEFAULT_NUMELEM_IN_CHUNK  2048


/**********************************************/
/*************** section II *******************/
/*This section  describes hash tables and their
  functions used in h4-h5 converter library APIs.*/
/*********************************************/

/*define three  kinds of hashtables. 
  1. struct table uses object reference as the key to handle whether this
  object is visited or not.
  2. struct name_table uses object name as the key to handle name clashings and
  dimensional scale dataset.
  3. struct modname_table uses name1 as the key and name2 is the associate 
  name with name1. 
*/
  
struct table {
  int ref;
  struct table *next;
  char *name;
  int flag;
};


struct name_table {
  char *name;
  struct name_table *next;
};

struct modname_table {
	char *name1;
	char *name2;
	struct modname_table *next;
};

/* struct error_list consists of error information:
1. errorstr: error string
2. filename: the file name which the error occurs at
3. linenum: line number that the error occurs
4. errorcode: error code 
5. next: pointer to the next level error struct
*/
 
struct error_list{
  char *errorstr;
  char *filename;
  int linenum;
  int errorcode;
  struct error_list* next;
};

/* this struct includes all hash table information and error 
handling information. This information will be initialized at 
H4toH5open and be close at H4toH5close. 
ID handler of HDF5 library will be used.*/

typedef struct {
  struct table* sds_hashtab;
  struct table* gr_hashtab;
  struct table* vg_hashtab;
  struct table* vd_hashtab;
  struct table* pal_hashtab;
  struct table* fakedim_hashtab;
  struct name_table* name_hashtab;
  struct name_table* puredim_hashtab;
  struct name_table* dimscale_hashtab;
  struct modname_table* moddim_hashtab;
  struct name_table* h5groupname_table;
  int32 file_id;
  int32 gr_id;
  int32 sd_id;
#ifdef HAVE_LIBHDFEOS
  const char *hdf4filename;
  int32 gd_fd;
  int32 sw_fd;
  int32 pt_fd;
  char *grid_list;
  char *swath_list;
  char *point_list;
  void *created_datasets;
  void *manglednames;
  void *eos2data;
  short has_swath;
#endif
  hid_t file5_id;
  struct error_list* h4toh5error;
  int error_suppressed;
}h4toh5id_t;

void  init_h4toh5id_t(h4toh5id_t *dt);


/**** SECTION III:
Utility functions for h4toh5 converter library. 
******************/

/**** PART I: General convenience functions. ******/
 /* These functions are: 

            1: h4toh5_ZeroMemory(zeroing out memory)

            2: mkstr(make HDF5 string type)

            3. conv_int_str(chang integer to string)

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

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

	    6: trans_obj_name(create HDF4 attribute name from
	    object type ,a constant and object reference number .)

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

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

void  h4toh5_ZeroMemory(void*s,size_t n); 
hid_t mkstr(hid_t h4toh5id,size_t size, H5T_str_t pad); 
int   conv_int_str(hid_t h4toh5id,uint32, char*); 
char* correct_name(hid_t h4toh5id,const char*);
char* get_groupname(hid_t h4toh5id,char*); 
char* trans_obj_name(hid_t h4toh5id,int32,int32); 
char* make_objname_no(hid_t h4toh5id,char*,const char*,const char*); 
char* make_objname_yes(hid_t h4toh5id,char*,const char*);


/********** h4toh5 utility functions. ******************* 
                PART II:
datatype conversion convenience functions:

These functions are:
1. h5string_to_int(from HDF5 string type to integer)
2. h4type_to_h5type(from HDF4 datatype to HDF5 datatype) 
**********/

herr_t h5string_to_int(hid_t h4toh5id,const int32, hid_t*,const
size_t,hid_t* ); 

herr_t h4type_to_h5type(hid_t h4toh5id,const int32
h4type, hid_t* h5memtype, size_t* h4memsize, size_t* h4size, hid_t
*h5type);



/********** h4toh5 utility functions. ******************* 
	    PART III:
HDF4 to HDF5 specific attribute conversion convenience
functions

These attributes are not  attributes of HDF4 object;
but some useful information to keep while doing HDF4 to HDF5
conversions. Please see h4toh5 mapping document for details.  

These functions are: 

1. h4_transnumattr 
(convert object reference number into an HDF5 attribute) 
2. h4_transpredattrs 
(convert predefined HDF4
information such as HDF4 OBJECT NAME, HDF4 OBJECT TYPE or HDF4 OBJECT
CLASS; they should all be converted into HDF5 string.)  
**********/

int h4_transpredattrs(hid_t h4toh5id,hid_t,const char *,char*data);
int h4_transnumattr(hid_t h4toh5id,hid_t h5g,const char *,uint16
group_ref);

/* Check if this attr flag is valid.
 * attr_flag should be between 0 and 4. 
 * See h4toh5.h for the value representation(H425_NOATTRS etc.)
 */
int is_valid_attr_flag(int attr_flag); 

hid_t H5Acreate_safe(hid_t h4toh5id, hid_t loc_id, const char *name, hid_t type_id, hid_t space_id, hid_t acpl_id);

int transattrs_split(hid_t h4toh5id, hid_t enclosing, const char *attrname, hid_t aspace, const char *data, int datalen);


/********** h4toh5 utility functions. ******************* 

	    PART IV: table management functions

 Since we have three tables, we will break
them into three subparts: 
(1) table 
(2) name table 
(3) modname table
*********************/


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

	     1. reference hash table: 

object reference as the key.
Fuctions: lookup,set_name,get_name lookup are used for checking
whether HDF4 objects are touched or not.  set_name and get_name 
will append and retrieve the name based on the lookup function. 

Objects used by this
function: SDS,image,vdata, vgroup,palette

	     2. name hash table: 

name as the key, has its own hash function
Functions: lookup_updatename, lookup_name, hashfun

lookup_updatename will append the name after it searches through 
the table without finding the name used by other HDF5 objects.

lookup_name will only check whether the name is used by other
HDF5 objects.

hashfun is a hashing function that gets the hash value based on 
the length of the name.

	     3. modname hash table: 

It was used in the converter to
deal with SDS dimensional scale dataset. Since name is unique for SDS
dimensional scale dataset, the name for SDS dimensional scale dataset
is used for the object key.  For converter API, since we allow users
to provide their own dimensional scale dataset name; so we have to
create another element in this table to append the absolute path of
the first touched SDS dimensional scale dataset name.

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

/******IV(1)

(1) table used object reference as the key 
These functions are: 

1. lookup (use object reference as the key to check whether the
table is looked up or not) 
2. get_name (obtain the name of the object
according to the object reference)
 3. set_name (store the name and object reference of the
object into the reference table) 
4. get_len_by_name(obtain the length of the Fakedim according to
the name.)
                                **********/

int lookup(hid_t h4toh5id,int,int,struct table*,int*); 

/* get name and set name for table. */ 

char* get_name(hid_t,int,int,struct table*,int*);
int   set_name(hid_t,int,int,struct table *,char*,int); 
char* lookup_len_update_name(hid_t,int,struct table *,const char*,short*); 
int   init_tab(hid_t,int,struct table*); 
int   freetable(int,struct table *);

/* This is for the initalization and freeing of the fakedim table*/ 
int   init_tab2(hid_t,struct table*); 
int   freetable2(struct table *);

/********IV(2) 
table used the object name as the key 
These functions are:
1. hash_fun 
2. lookup_updatename (use name as the key to check whether
the table is looked up or not) 
3. lookup_name
**********/

int hash_fun(const char*name,int size); 
int lookup_name(hid_t h4toh5id,char*,int,struct name_table*);
int lookup_updatename(hid_t h4toh5id,const char*, int,struct name_table*); 
int freenametable(int, struct name_table*);
int init_nametab(hid_t h4toh5id,int,struct name_table*);

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

int   modlookup_updatename(hid_t h4toh5id,char*, char*,int,struct modname_table*);
char* get_modname2(hid_t h4toh5id,char*name,int size,struct modname_table*);
int   freemodnametable(int,struct modname_table*);
int init_modnametab(hid_t h4toh5id,int,struct modname_table*);


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

/*1. dimension scale functions*/
#if 0
#ifdef USE_DIMSCALE_APIS
hid_t create_pure_fake_dim_scale(hid_t,char*,int,int);
hid_t create_pure_dim_scale(hid_t,int,int);
hid_t create_dim_scale(hid_t,int,int);
#endif
#endif

/*2. other functions */
char* get_obj_aboname(hid_t h4toh5id,char*,char*,const char*,const char*,struct name_table*,int,int*);
int free_allhashmemory(h4toh5id_t*);
hid_t get_h5groupid(const char*,hid_t,int);
char* get_h5datasetname(hid_t h4toh5id,const char*,const char*,uint16,const char*,int,int*);
char* get_orih5datasetname(hid_t h4toh5id, uint16,const char*,int);

int   checkvloneobject(hid_t,int32);
int   checkvringobject(hid_t,int32);
int   vgcheck_object(hid_t,int32);

/*** PART VI. error handling fuctions. ****/
int   H4toH5error_set(h4toh5id_t*,int errorcode, const char*errorstr,const char* filename,int linenum);
int   H4toH5error_reset(hid_t h4toh5id);

int   H4toH5error_suppress(hid_t h4toh5id, int suppress);
int   H4toH5error_set0(hid_t h4toh5id, int errorcode, const char *filename, int linenum);
int   H4toH5error_set1(hid_t h4toh5id, int errorcode, const char *e1, const char *filename, int linenum);
int   H4toH5error_set2(hid_t h4toh5id, int errorcode, const char *e1, const char *e2, const char *filename, int linenum);
int   H4toH5error_set3(hid_t h4toh5id, int errorcode, const char *e1, const char *e2, const char *e3, const char *filename, int linenum);
int   H4toH5error_set4(hid_t h4toh5id, int errorcode, const char *e1, const char *e2, const char *e3, const char *e4, const char *filename, int linenum);
int   H4toH5error_set5(hid_t h4toh5id, int errorcode, const char *e1, const char *e2, const char *e3, const char *e4, const char *e5, const char *filename, int linenum);
int   H4toH5error_nomem1(hid_t h4toh5id, const char *errorstr1, const char *filename, int linenum);
/* These macros hide __FILE__, __LINE__ and h4toh5id given that h4toh5id is defined in the caller */
#define H4TOH5ERROR_SET0(code)  H4toH5error_set0(h4toh5id, code, __FILE__, __LINE__)
#define H4TOH5ERROR_SET1(code, msg)  H4toH5error_set1(h4toh5id, code, msg, __FILE__, __LINE__)
#define H4TOH5ERROR_SET2(code, msg, a1)  H4toH5error_set2(h4toh5id, code, msg, a1, __FILE__, __LINE__)
#define H4TOH5ERROR_SET3(code, msg, a1, a2)  H4toH5error_set3(h4toh5id, code, msg, a1, a2, __FILE__, __LINE__)
#define H4TOH5ERROR_SET4(code, msg, a1, a2, a3)  H4toH5error_set4(h4toh5id, code, msg, a1, a2, a3, __FILE__, __LINE__)
#define H4TOH5ERROR_SET5(code, msg, a1, a2, a3, a4)  H4toH5error_set5(h4toh5id, code, msg, a1, a2, a3, a4, __FILE__, __LINE__)
#define H4TOH5ERROR_NOMEM1(msg)  H4toH5error_nomem1(h4toh5id, msg, __FILE__, __LINE__)

int   H4toH5assert_failure(const char *filename, int linenum);
#define H4TOH5ASSERT(e)  { if (!(e)) H4toH5assert_failure(__FILE__, __LINE__); }
#define H4TOH5ASSERT_RANGE(e, ge, l)  { H4TOH5ASSERT((ge) <= (e) && (e) < (l)) }

/*int h4toh5Eget(hid_t h4toh5id);*/
int   freeerror_list(struct error_list *list);
char* get_codestr(int);


/*** PART VII. helper functions for obtain object name APIs***/

char* H4toH5get_clash_groupname(hid_t,int32,char*);
char* H4toH5get_clash_SDSname(hid_t,int32,char*);
char* H4toH5get_clash_imagename(hid_t,int32,char*);
char* H4toH5get_clash_vdataname(hid_t,int32,char*);
char* H4toH5get_clash_palname(hid_t,int32,char*);


/*** adding a macro for detecting overflow when casting between types, 
     following HDF5 library approach***/

#define H425_CHECK_OVERFLOW(var,vartype,casttype) \
{                                                 \
  casttype _tmp_overflow=(casttype)(var);         \
  assert ((var)==(vartype)_tmp_overflow);          \
}

/* Visual Studio gives too many security warnings saying that str... functions are dangerous.
 * Too many false positives may distract us from finding real warnings, and I'd like to suppress warnings
 */
#ifdef _MSC_VER
#pragma warning(disable:4996)
#endif

#endif






