    001/*****************************************************************************
    002 * Copyright by The HDF Group.                                               *
    003 * Copyright by the Board of Trustees of the University of Illinois.         *
    004 * All rights reserved.                                                      *
    005 *                                                                           *
    006 * This file is part of the HDF Java Products distribution.                  *
    007 * The full copyright notice, including terms governing use, modification,   *
    008 * and redistribution, is contained in the COPYING file, which can be found  *
    009 * at the root of the source code distribution tree,                         *
    010 * or in https://www.hdfgroup.org/licenses.                                  *
    011 * If you do not have access to either file, you may request a copy from     *
    012 * help@hdfgroup.org.                                                        *
    013 ****************************************************************************/
    014
    015package hdf.object.h5;
    016
    017import java.lang.reflect.Array;
    018import java.math.BigDecimal;
    019import java.math.BigInteger;
    020import java.math.MathContext;
    021import java.util.ArrayList;
    022import java.util.Arrays;
    023import java.util.BitSet;
    024import java.util.HashMap;
    025import java.util.Iterator;
    026import java.util.List;
    027import java.util.Map.Entry;
    028import java.util.Objects;
    029import java.util.Vector;
    030
    031import org.slf4j.Logger;
    032import org.slf4j.LoggerFactory;
    033
    034import hdf.hdf5lib.H5;
    035import hdf.hdf5lib.HDF5Constants;
    036import hdf.hdf5lib.HDFArray;
    037import hdf.hdf5lib.HDFNativeData;
    038import hdf.hdf5lib.exceptions.HDF5Exception;
    039import hdf.hdf5lib.exceptions.HDF5LibraryException;
    040import hdf.hdf5lib.structs.H5O_info_t;
    041import hdf.hdf5lib.structs.H5O_token_t;
    042
    043import hdf.object.Attribute;
    044import hdf.object.CompoundDS;
    045import hdf.object.Datatype;
    046import hdf.object.FileFormat;
    047
    048import hdf.object.h5.H5MetaDataContainer;
    049
    050/**
    051 * This class defines HDF5 datatype characteristics and APIs for a data type. This class provides several methods to
    052 * convert an HDF5 datatype identifier to a datatype object, and vice versa. A datatype object is described by four
    053 * basic fields: datatype class, size, byte order, and sign, while an HDF5 datatype is presented by a datatype
    054 * identifier.
    055 *
    056 * @version 1.1 9/4/2007
    057 * @author Peter X. Cao
    058 */
    059public class H5Datatype extends Datatype
    060{
    061    private static final long serialVersionUID = -750546422258749792L;
    062
    063    private static final Logger log = LoggerFactory.getLogger(H5Datatype.class);
    064
    065    /**
    066     * The metadata object for this data object. Members of the metadata are instances of Attribute.
    067     */
    068    private H5MetaDataContainer objMetadata;
    069
    070    /**
    071     * The dimension sizes of the reference object
    072     */
    073    protected long[] refdims;
    074
    075    /** the datatype is an object reference */
    076    private boolean isRefObj = false;
    077
    078    /** the datatype is a region reference */
    079    private boolean isRegRef = false;
    080
    081    /** the datatype is a standard reference */
    082    private boolean isStdRef = false;
    083
    084    /** the object properties */
    085    private H5O_info_t objInfo;
    086
    087    /**
    088     * The native class of the datatype.
    089     */
    090    private int nativeClass = -1;
    091
    092    /** The native Precision properties of the number datatype. */
    093    private long nativePrecision = 0;
    094    /** The native Offset properties of the number datatype. */
    095    private int nativeOffset = -1;
    096    /** The native PadLSB properties of the number datatype. */
    097    private int nativePadLSB = -1;
    098    /** The native PadMSB properties of the number datatype. */
    099    private int nativePadMSB = -1;
    100
    101    /** The native ebias properties of the float datatype. */
    102    private long nativeFPebias = 0;
    103    /** The native spos properties of the float datatype. */
    104    private long nativeFPspos = -1;
    105    /** The native epos properties of the float datatype. */
    106    private long nativeFPepos = -1;
    107    /** The native esize properties of the float datatype. */
    108    private long nativeFPesize = -1;
    109    /** The native mpos properties of the float datatype. */
    110    private long nativeFPmpos = -1;
    111    /** The native msize properties of the float datatype. */
    112    private long nativeFPmsize = -1;
    113    /** The native norm properties of the float datatype. */
    114    private int nativeFPnorm = -1;
    115    /** The native inpad properties of the float datatype. */
    116    private int nativeFPinpad = -1;
    117
    118    /** The native padding properties of the string datatype. */
    119    private int nativeStrPad = -1;
    120    /** The native CSET properties of the string datatype. */
    121    private int nativeStrCSET = -1;
    122
    123    /**
    124     * The tag for an opaque datatype.
    125     */
    126    private String opaqueTag = null;
    127
    128    /**
    129     * Constructs an named HDF5 data type object for a given file, dataset name and group path. The datatype object
    130     * represents an existing named datatype in file. For example,
    131     *
    132     * <pre>
    133     * new H5Datatype(file, "dtype1", "/g0")
    134     * </pre>
    135     *
    136     * constructs a datatype object that corresponds to the dataset,"dset1", at group "/g0".
    137     *
    138     * @param theFile
    139     *                the file that contains the datatype.
    140     * @param theName
    141     *                the name of the dataset such as "dset1".
    142     * @param thePath
    143     *                the group path to the dataset such as "/g0/".
    144     */
    145    public H5Datatype(FileFormat theFile, String theName, String thePath) {
    146        this(theFile, theName, thePath, null);
    147    }
    148
    149    /**
    150     * @deprecated Not for public use in the future. <br>
    151     *             Using {@link #H5Datatype(FileFormat, String, String)}
    152     * @param theFile
    153     *                the file that contains the datatype.
    154     * @param theName
    155     *                the name of the dataset such as "dset1".
    156     * @param thePath
    157     *                the group path to the dataset such as "/g0/".
    158     * @param oid
    159     *                the oid of the dataset.
    160     */
    161    @Deprecated
    162    public H5Datatype(FileFormat theFile, String theName, String thePath, long[] oid) {
    163        super(theFile, theName, thePath, oid);
    164        objMetadata = new H5MetaDataContainer(theFile, theName, thePath, this);
    165
    166        if (theFile != null) {
    167            if (oid == null) {
    168                // retrieve the object ID
    169                byte[] refBuf = null;
    170                try {
    171                    refBuf = H5.H5Rcreate_object(theFile.getFID(), this.getFullName(), HDF5Constants.H5P_DEFAULT);
    172                    this.oid = HDFNativeData.byteToLong(refBuf);
    173                    log.trace("constructor REF {} to OID {}", refBuf, this.oid);
    174                }
    175                catch (Exception ex) {
    176                    log.debug("constructor ID {} for {} failed H5Rcreate_object", theFile.getFID(), this.getFullName());
    177                }
    178                finally {
    179                    if (refBuf != null)
    180                        H5.H5Rdestroy(refBuf);
    181                }
    182            }
    183            log.trace("constructor OID {}", this.oid);
    184            try {
    185                objInfo = H5.H5Oget_info_by_name(theFile.getFID(), this.getFullName(), HDF5Constants.H5O_INFO_BASIC,
    186                        HDF5Constants.H5P_DEFAULT);
    187            }
    188            catch (Exception ex) {
    189                objInfo = new H5O_info_t(-1L, null, 0, 0, 0L, 0L, 0L, 0L, 0L);
    190            }
    191
    192            long tid = HDF5Constants.H5I_INVALID_HID;
    193            try {
    194                tid = open();
    195            }
    196            catch (Exception ex) {
    197                log.debug("constructor H5Topen() failure");
    198            }
    199            finally {
    200                close(tid);
    201            }
    202        }
    203        else {
    204            this.oid = null;
    205            objInfo = new H5O_info_t(-1L, null, 0, 0, 0L, 0L, 0L, 0L, 0L);
    206        }
    207    }
    208
    209    /**
    210     * Constructs a Datatype with specified class, size, byte order and sign. The following is a list of a few examples
    211     * of H5Datatype.
    212     * <ol>
    213     * <li>to create unsigned native integer<br>
    214     * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
    215     * <li>to create 16-bit signed integer with big endian<br>
    216     * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
    217     * <li>to create native float<br>
    218     * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
    219     * <li>to create 64-bit double<br>
    220     * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
    221     * </ol>
    222     *
    223     * @param tclass
    224     *               the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    225     * @param tsize
    226     *               the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. Valid values are
    227     *               NATIVE or a positive value. For string datatypes, -1 is also a valid value (to create a
    228     *               variable-length string).
    229     * @param torder
    230     *               the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX, ORDER_NONE and
    231     *               NATIVE.
    232     * @param tsign
    233     *               the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
    234     * @throws Exception
    235     *                   if there is an error
    236     */
    237    public H5Datatype(int tclass, int tsize, int torder, int tsign) throws Exception {
    238        this(tclass, tsize, torder, tsign, null);
    239    }
    240
    241    /**
    242     * Constructs a Datatype with specified class, size, byte order and sign. The following is a list of a few examples
    243     * of H5Datatype.
    244     * <ol>
    245     * <li>to create unsigned native integer<br>
    246     * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
    247     * <li>to create 16-bit signed integer with big endian<br>
    248     * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
    249     * <li>to create native float<br>
    250     * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
    251     * <li>to create 64-bit double<br>
    252     * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
    253     * </ol>
    254     *
    255     * @param tclass
    256     *               the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    257     * @param tsize
    258     *               the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. Valid values are
    259     *               NATIVE or a positive value. For string datatypes, -1 is also a valid value (to create a
    260     *               variable-length string).
    261     * @param torder
    262     *               the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX, ORDER_NONE and
    263     *               NATIVE.
    264     * @param tsign
    265     *               the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
    266     * @param tbase
    267     *               the base datatype of the new datatype
    268     * @throws Exception
    269     *                   if there is an error
    270     */
    271    public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) throws Exception {
    272        this(tclass, tsize, torder, tsign, tbase, null);
    273    }
    274
    275    /**
    276     * Constructs a Datatype with specified class, size, byte order and sign. The following is a list of a few examples
    277     * of H5Datatype.
    278     * <ol>
    279     * <li>to create unsigned native integer<br>
    280     * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
    281     * <li>to create 16-bit signed integer with big endian<br>
    282     * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
    283     * <li>to create native float<br>
    284     * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
    285     * <li>to create 64-bit double<br>
    286     * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
    287     * </ol>
    288     *
    289     * @param tclass
    290     *               the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    291     * @param tsize
    292     *               the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. Valid values are
    293     *               NATIVE or a positive value. For string datatypes, -1 is also a valid value (to create a
    294     *               variable-length string).
    295     * @param torder
    296     *               the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX, ORDER_NONE and
    297     *               NATIVE.
    298     * @param tsign
    299     *               the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
    300     * @param tbase
    301     *               the base datatype of the new datatype
    302     * @param pbase
    303     *               the parent datatype of the new datatype
    304     * @throws Exception
    305     *                   if there is an error
    306     */
    307    public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase) throws Exception {
    308        super(tclass, tsize, torder, tsign, tbase, pbase);
    309        datatypeDescription = getDescription();
    310    }
    311
    312    /**
    313     * Constructs a Datatype with a given native datatype identifier. For example, if the datatype identifier is a
    314     * 32-bit unsigned integer created from HDF5,
    315     *
    316     * <pre>
    317     * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
    318     * Datatype dtype = new Datatype(tid);
    319     * </pre>
    320     *
    321     * will construct a datatype equivalent to new Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE,
    322     * Datatype.SIGN_NONE);
    323     *
    324     * @see #fromNative(long nativeID)
    325     * @param theFile
    326     *                 the file that contains the datatype.
    327     * @param nativeID
    328     *                 the native datatype identifier.
    329     * @throws Exception
    330     *                   if there is an error
    331     */
    332    public H5Datatype(FileFormat theFile, long nativeID) throws Exception {
    333        this(theFile, nativeID, null);
    334    }
    335
    336    /**
    337     * Constructs a Datatype with a given native datatype identifier. For example, if the datatype identifier is a
    338     * 32-bit unsigned integer created from HDF5,
    339     *
    340     * <pre>
    341     * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
    342     * Datatype dtype = new Datatype(tid);
    343     * </pre>
    344     *
    345     * will construct a datatype equivalent to new Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE,
    346     * Datatype.SIGN_NONE);
    347     *
    348     * @see #fromNative(long nativeID)
    349     * @param theFile
    350     *                 the file that contains the datatype.
    351     * @param nativeID
    352     *                 the native datatype identifier.
    353     * @param pbase
    354     *                 the parent datatype of the new datatype
    355     * @throws Exception
    356     *                   if there is an error
    357     */
    358    public H5Datatype(FileFormat theFile, long nativeID, Datatype pbase) throws Exception {
    359        super(theFile, nativeID, pbase);
    360        fromNative(nativeID);
    361        datatypeDescription = getDescription();
    362    }
    363
    364    /**
    365     * Opens access to a named datatype. It calls H5.H5Topen(loc, name).
    366     *
    367     * @return the datatype identifier if successful; otherwise returns negative value.
    368     * @see hdf.hdf5lib.H5#H5Topen(long, String, long)
    369     */
    370    @Override
    371    public long open() {
    372        long tid = HDF5Constants.H5I_INVALID_HID;
    373
    374        if (fileFormat != null) {
    375            try {
    376                tid = H5.H5Topen(getFID(), getFullName(), HDF5Constants.H5P_DEFAULT);
    377                fromNative(tid);
    378                log.trace("open(): tid={}", tid);
    379            }
    380            catch (HDF5Exception ex) {
    381                log.debug("open(): Failed to open datatype {}", getFullName(), ex);
    382                tid = HDF5Constants.H5I_INVALID_HID;
    383            }
    384        }
    385
    386        return tid;
    387    }
    388
    389    /**
    390     * Closes a datatype identifier. It calls H5.H5close(tid).
    391     *
    392     * @param tid
    393     *            the datatype ID to close
    394     */
    395    @Override
    396    public void close(long tid) {
    397        if (tid >= 0) {
    398            try {
    399                H5.H5Tclose(tid);
    400            }
    401            catch (HDF5Exception ex) {
    402                log.debug("close(): H5Tclose(tid {}) failure: ", tid, ex);
    403            }
    404        }
    405    }
    406
    407    /**
    408     * Get the token for this object.
    409     *
    410     * @return true if it has any attributes, false otherwise.
    411     */
    412    public long[] getToken() {
    413        H5O_token_t token = objInfo.token;
    414        return HDFNativeData.byteToLong(token.data);
    415    }
    416
    417    /**
    418     * Check if the object has any attributes attached.
    419     *
    420     * @return true if it has any attributes, false otherwise.
    421     */
    422    @Override
    423    public boolean hasAttribute() {
    424        objInfo.num_attrs = objMetadata.getObjectAttributeSize();
    425
    426        if (objInfo.num_attrs < 0) {
    427            long tid = open();
    428            if (tid > 0) {
    429                try {
    430                    objInfo = H5.H5Oget_info(tid);
    431                }
    432                catch (Exception ex) {
    433                    objInfo.num_attrs = 0;
    434                    log.debug("hasAttribute(): get object info failure: ", ex);
    435                }
    436                finally {
    437                    close(tid);
    438                }
    439                objMetadata.setObjectAttributeSize((int) objInfo.num_attrs);
    440            }
    441            else {
    442                log.debug("hasAttribute(): could not open group");
    443            }
    444        }
    445
    446        log.trace("hasAttribute(): nAttributes={}", objInfo.num_attrs);
    447        return (objInfo.num_attrs > 0);
    448    }
    449
    450    /**
    451     * Converts values in an Enumeration Datatype to names. This method searches the identified enumeration datatype for
    452     * the values appearing in <code>inValues</code> and returns the names corresponding to those values. If a given
    453     * value is not found in the enumeration datatype, the name corresponding to that value will be set to
    454     * <code>"ENUM ERR value"</code> in the string array that is returned. If the method fails in general, null will be
    455     * returned instead of a String array. An empty <code>inValues</code> parameter would cause general failure.
    456     *
    457     * @param inValues
    458     *                 The array of enumerations values to be converted.
    459     * @return The string array of names if successful; otherwise return null.
    460     * @throws HDF5Exception
    461     *                       If there is an error at the HDF5 library level.
    462     */
    463    public String[] convertEnumValueToName(Object inValues)
    464            throws HDF5Exception {
    465        log.trace("convertEnumValueToName() inValues={} start", inValues);
    466
    467        if (inValues == null) {
    468            log.debug("convertEnumValueToName() failure: in values null ");
    469            return null;
    470        }
    471
    472        int inSize = 0;
    473        String[] outNames = null;
    474        String cName = inValues.getClass().getName();
    475        boolean isArray = cName.lastIndexOf('[') >= 0;
    476        if (isArray)
    477            inSize = Array.getLength(inValues);
    478        else
    479            inSize = 1;
    480
    481        if (inSize <= 0) {
    482            log.debug("convertEnumValueToName() failure: inSize length invalid");
    483            log.debug("convertEnumValueToName(): inValues={} inSize={}", inValues, inSize);
    484            return null;
    485        }
    486
    487        if (enumMembers == null
    488                || enumMembers.size() <= 0) {
    489            log.debug("convertEnumValueToName(): no members");
    490            return null;
    491        }
    492
    493        log.trace("convertEnumValueToName(): inSize={} nMembers={} enums={}", inSize, enumMembers.size(), enumMembers);
    494        outNames = new String[inSize];
    495        for (int i = 0; i < inSize; i++) {
    496            if (isArray) {
    497                if (enumMembers.containsKey(String.valueOf(Array.get(inValues, i))))
    498                    outNames[i] = enumMembers.get(String.valueOf(Array.get(inValues, i)));
    499                else
    500                    outNames[i] = "**ENUM ERR " + Array.get(inValues, i) + "**";
    501            }
    502            else {
    503                if (enumMembers.containsKey(String.valueOf(inValues)))
    504                    outNames[i] = enumMembers.get(String.valueOf(inValues));
    505                else
    506                    outNames[i] = "**ENUM ERR " + inValues + "**";
    507            }
    508        }
    509
    510        return outNames;
    511    }
    512
    513    /**
    514     * Converts names in an Enumeration Datatype to values. This method searches the identified enumeration datatype for
    515     * the names appearing in <code>inValues</code> and returns the values corresponding to those names.
    516     *
    517     * @param in
    518     *           The array of enumerations names to be converted.
    519     * @return The int array of values if successful; otherwise return null.
    520     * @throws HDF5Exception
    521     *                       If there is an error at the HDF5 library level.
    522     */
    523    public Object[] convertEnumNameToValue(String[] in)
    524            throws HDF5Exception {
    525        int size = 0;
    526
    527        if (in == null) {
    528            log.debug("convertEnumNameToValue() failure: in values null");
    529            return null;
    530        }
    531
    532        if ((size = Array.getLength(in)) <= 0) {
    533            log.debug("convertEnumNameToValue() failure: in size not valid");
    534            return null;
    535        }
    536
    537        if (enumMembers == null
    538                || enumMembers.size() <= 0) {
    539            log.debug("convertEnumNameToValue(): no members");
    540            return null;
    541        }
    542
    543        Object[] out = null;
    544        if (datatypeSize == 1)
    545            out = new Byte[size];
    546        else if (datatypeSize == 2)
    547            out = new Short[size];
    548        else if (datatypeSize == 4)
    549            out = new Integer[size];
    550        else if (datatypeSize == 8)
    551            out = new Long[size];
    552        else
    553            out = new Object[size];
    554
    555        for (int i = 0; i < size; i++) {
    556            if (in[i] == null
    557                    || in[i].length() <= 0)
    558                continue;
    559
    560            for (Entry<String, String> entry : enumMembers.entrySet()) {
    561                if (Objects.equals(in[i], entry.getValue())) {
    562                    if (datatypeSize == 1) {
    563                        log.trace("convertEnumNameToValue(): ENUM is H5T_NATIVE_INT8");
    564                        out[i] = Byte.parseByte(entry.getKey());
    565                    }
    566                    else if (datatypeSize == 2) {
    567                        log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT16");
    568                        out[i] = Short.parseShort(entry.getKey());
    569                    }
    570                    else if (datatypeSize == 4) {
    571                        log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT32");
    572                        out[i] = Integer.parseInt(entry.getKey());
    573                    }
    574                    else if (datatypeSize == 8) {
    575                        log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT64");
    576                        out[i] = Long.parseLong(entry.getKey());
    577                    }
    578                    else {
    579                        log.debug("convertEnumNameToValue(): enum datatypeSize incorrect");
    580                        out[i] = -1;
    581                    }
    582                    break;
    583                }
    584            }
    585        }
    586
    587        return out;
    588    }
    589
    590    /**
    591     * Convert from an array of BigDecimal into an array of bytes
    592     *
    593     * @param start
    594     *              The position in the input array of BigDecimal to start
    595     * @param len
    596     *              The number of 'BigDecimal' to convert
    597     * @param data
    598     *              The input array of BigDecimal
    599     * @return an array of bytes
    600     */
    601    public byte[] bigDecimalToByte(int start, int len, BigDecimal[] data) {
    602        int ii;
    603        byte[] bd = new byte[(int) datatypeSize];
    604        byte[] bdconv = new byte[(int) datatypeSize];
    605        byte[] bdbytes = new byte[(int) datatypeSize * len];
    606
    607        for (ii = 0; ii < len; ii++) {
    608            BigDecimal entry = data[start + ii];
    609            bdconv = convertBigDecimalToByte(entry);
    610            /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */
    611            if (datatypeOrder == ORDER_BE) {
    612                int k = 0;
    613                for (int j = (int) datatypeSize - 1; j >= 0; j--)
    614                    bd[k++] = bdconv[j];
    615            }
    616            else {
    617                try {
    618                    System.arraycopy(bdconv, 0, bd, 0, (int) datatypeSize);
    619                }
    620                catch (Exception err) {
    621                    log.trace("bigDecimalToByte(): arraycopy failure: ", err);
    622                }
    623            }
    624            try {
    625                System.arraycopy(bd, 0, bdbytes, ii * 16, 16);
    626            }
    627            catch (Exception err) {
    628                log.trace("bigDecimalToByte(): arraycopy failure: ", err);
    629            }
    630        }
    631        return bdbytes;
    632    }
    633
    634    /**
    635     * Convert from a single BigDecimal object from an array of BigDecimal into an array of bytes
    636     *
    637     * @param start
    638     *              The position in the input array of BigDecimal to start
    639     * @param data
    640     *              The input Float
    641     * @return an array of bytes
    642     */
    643    public byte[] bigDecimalToByte(BigDecimal[] data, int start) {
    644        byte[] bdbytes = new byte[(int) datatypeSize];
    645        bdbytes = bigDecimalToByte(start, 1, data);
    646        return bdbytes;
    647    }
    648
    649    /**
    650     * Convert a BigDecimal to a byte array .
    651     *
    652     * @param num
    653     *            The BigDecimal number to convert
    654     * @return A byte array representing the BigDecimal.
    655     */
    656    public byte[] convertBigDecimalToByte(BigDecimal num) {
    657        BigInteger sig = new BigInteger(num.unscaledValue().toString());
    658        byte[] bsig = sig.toByteArray();
    659        int scale = num.scale();
    660        byte[] bscale = new byte[] { (byte) (scale >>> 24), (byte) (scale >>> 16), (byte) (scale >>> 8),
    661                (byte) (scale) };
    662        byte[] both = new byte[bscale.length + bsig.length];
    663        try {
    664            System.arraycopy(bscale, 0, both, 0, bscale.length);
    665            System.arraycopy(bsig, 0, both, bscale.length, bsig.length);
    666        }
    667        catch (Exception err) {
    668            log.trace("convertBigDecimalToByte(): arraycopy failure: ", err);
    669        }
    670        return both;
    671    }
    672
    673    /**
    674     * Convert a range from an array of bytes into an array of BigDecimal
    675     *
    676     * @param start
    677     *              The position in the input array of bytes to start
    678     * @param len
    679     *              The number of 'BigDecimal' to convert
    680     * @param data
    681     *              The input array of bytes
    682     * @return an array of 'len' BigDecimal
    683     */
    684    public BigDecimal[] byteToBigDecimal(int start, int len, byte[] data) {
    685        int ii;
    686        byte[] bd = new byte[(int) datatypeSize];
    687        BigDecimal[] BDarray = new BigDecimal[len];
    688
    689        for (ii = 0; ii < len; ii++) {
    690            int rawpos = (start + ii) * (int) datatypeSize;
    691            /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */
    692            if (datatypeOrder == ORDER_BE) {
    693                int k = 0;
    694                for (int j = (int) datatypeSize - 1; j >= 0; j--)
    695                    bd[k++] = data[rawpos + j];
    696            }
    697            else {
    698                try {
    699                    System.arraycopy(data, rawpos, bd, 0, (int) datatypeSize);
    700                }
    701                catch (Exception err) {
    702                    log.trace("byteToBigDecimal(): arraycopy failure: ", err);
    703                }
    704            }
    705            BDarray[ii] = convertByteToBigDecimal(bd);
    706        }
    707        return BDarray;
    708    }
    709
    710    /**
    711     * Convert 4 bytes from an array of bytes into a single BigDecimal
    712     *
    713     * @param start
    714     *              The position in the input array of bytes to start
    715     * @param data
    716     *              The input array of bytes
    717     * @return The BigDecimal value of the bytes.
    718     */
    719    public BigDecimal byteToBigDecimal(byte[] data, int start) {
    720        BigDecimal[] bdval = new BigDecimal[1];
    721        bdval = byteToBigDecimal(start, 1, data);
    722        return (bdval[0]);
    723    }
    724
    725    /**
    726     * Convert byte array data to a BigDecimal.
    727     *
    728     * @param raw
    729     *            The byte array to convert to a BigDecimal
    730     * @return A BigDecimal representing the byte array.
    731     */
    732    public BigDecimal convertByteToBigDecimal(byte[] raw) {
    733        BitSet rawset = BitSet.valueOf(raw);
    734
    735        boolean sign = rawset.get(nativeOffset + (int) nativeFPspos);
    736        BitSet mantissaset = rawset.get(nativeOffset + (int) nativeFPmpos,
    737                nativeOffset + (int) nativeFPmpos + (int) nativeFPmsize);
    738        BitSet exponentset = rawset.get(nativeOffset + (int) nativeFPepos,
    739                nativeOffset + (int) nativeFPepos + (int) nativeFPesize);
    740        byte[] expraw = Arrays.copyOf(exponentset.toByteArray(), (int) (nativeFPesize + 7) / 8);
    741        byte[] bexp = new byte[expraw.length];
    742        /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */
    743        if (datatypeOrder == ORDER_LE) {
    744            int k = 0;
    745            for (int j = expraw.length - 1; j >= 0; j--)
    746                bexp[k++] = expraw[j];
    747        }
    748        else {
    749            try {
    750                System.arraycopy(expraw, 0, bexp, 0, expraw.length);
    751            }
    752            catch (Exception err) {
    753                log.trace("convertByteToBigDecimal(): arraycopy failure: ", err);
    754            }
    755        }
    756        BigInteger bscale = new BigInteger(bexp);
    757        long scale = bscale.longValue();
    758        scale -= nativeFPebias;
    759        double powscale = Math.pow(2, scale);
    760
    761        byte[] manraw = Arrays.copyOf(mantissaset.toByteArray(), (int) (nativeFPmsize + 7) / 8);
    762        byte[] bman = new byte[manraw.length];
    763        /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */
    764        if (datatypeOrder == ORDER_BE) {
    765            int k = 0;
    766            for (int j = manraw.length - 1; j >= 0; j--)
    767                bman[k++] = manraw[j];
    768        }
    769        else {
    770            try {
    771                System.arraycopy(manraw, 0, bman, 0, manraw.length);
    772            }
    773            catch (Exception err) {
    774                log.trace("convertByteToBigDecimal(): arraycopy failure: ", err);
    775            }
    776        }
    777        BitSet manset = BitSet.valueOf(bman);
    778
    779        // calculate mantissa value
    780        double val = 0.0;
    781        for (int i = 0; i < (int) nativeFPmsize; i++) {
    782            if (manset.get((int) nativeFPmsize - 1 - i))
    783                val += Math.pow(2, -(i));
    784        }
    785        if (nativeFPnorm == HDF5Constants.H5T_NORM_IMPLIED
    786                || nativeFPnorm == HDF5Constants.H5T_NORM_MSBSET)
    787            val += 1;
    788        BigDecimal sig = BigDecimal.valueOf(val);
    789        if (sign)
    790            sig.negate(MathContext.DECIMAL128);
    791        return sig.multiply(new BigDecimal(powscale, MathContext.DECIMAL128));
    792    }
    793
    794    /*
    795     * (non-Javadoc)
    796     * @see hdf.object.Datatype#fromNative(int)
    797     */
    798    @Override
    799    public void fromNative(long tid) {
    800        log.trace("fromNative(): start: tid={}", tid);
    801        long tsize = -1;
    802        int torder = -1;
    803        boolean isChar = false;
    804        boolean isUchar = false;
    805
    806        if (tid < 0) {
    807            datatypeClass = CLASS_NO_CLASS;
    808        }
    809        else {
    810            try {
    811                nativeClass = H5.H5Tget_class(tid);
    812                tsize = H5.H5Tget_size(tid);
    813                isVariableStr = H5.H5Tis_variable_str(tid);
    814                isVLEN = false;
    815                log.trace("fromNative(): tclass={}, tsize={}, torder={}, isVLEN={}", nativeClass, tsize, torder,
    816                        isVLEN);
    817                if (H5.H5Tcommitted(tid)) {
    818                    isNamed = true;
    819                    try {
    820                        setFullname(null, H5.H5Iget_name(tid));
    821                    }
    822                    catch (Exception nex) {
    823                        log.debug("fromNative(): setName failure: {}", nex.getMessage());
    824                    }
    825                    log.trace("fromNative(): path={} name={}", this.getPath(), this.getName());
    826                }
    827                log.trace("fromNative(): isNamed={}", isNamed());
    828            }
    829            catch (Exception ex) {
    830                log.debug("fromNative(): failure: ", ex);
    831                datatypeClass = CLASS_NO_CLASS;
    832            }
    833
    834            try {
    835                isUchar = H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_UCHAR);
    836                isChar = (H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_CHAR)
    837                        || isUchar);
    838                log.trace("fromNative(): tclass={}, tsize={}, torder={}, isUchar={}, isChar={}", nativeClass, tsize,
    839                        torder, isUchar, isChar);
    840            }
    841            catch (Exception ex) {
    842                log.debug("fromNative(): native char type failure: ", ex);
    843            }
    844
    845            datatypeOrder = HDF5Constants.H5T_ORDER_NONE;
    846            boolean IsAtomic = datatypeClassIsAtomic(nativeClass);
    847            if (IsAtomic
    848                    || (nativeClass == HDF5Constants.H5T_COMPOUND)) {
    849                try {
    850                    torder = H5.H5Tget_order(tid);
    851                    datatypeOrder = (torder == HDF5Constants.H5T_ORDER_BE) ? ORDER_BE : ORDER_LE;
    852                }
    853                catch (Exception ex) {
    854                    log.debug("fromNative(): get_order failure: ", ex);
    855                }
    856            }
    857
    858            if (IsAtomic
    859                    && !datatypeClassIsOpaque(nativeClass)) {
    860                try {
    861                    nativePrecision = H5.H5Tget_precision_long(tid);
    862                }
    863                catch (Exception ex) {
    864                    log.debug("fromNative(): get_precision failure: ", ex);
    865                }
    866
    867                try {
    868                    nativeOffset = H5.H5Tget_offset(tid);
    869                }
    870                catch (Exception ex) {
    871                    log.debug("fromNative(): get_offset failure: ", ex);
    872                }
    873
    874                try {
    875                    int[] pads = new int[2];
    876                    H5.H5Tget_pad(tid, pads);
    877                    nativePadLSB = pads[0];
    878                    nativePadMSB = pads[1];
    879                }
    880                catch (Exception ex) {
    881                    log.debug("fromNative(): get_pad failure: ", ex);
    882                }
    883            }
    884
    885            log.trace("fromNative(): isUchar={}, nativePrecision={}, nativeOffset={}, nativePadLSB={}, nativePadMSB={}",
    886                    isUchar, nativePrecision, nativeOffset, nativePadLSB, nativePadMSB);
    887
    888            datatypeSign = NATIVE; // default
    889            if (nativeClass == HDF5Constants.H5T_ARRAY) {
    890                long tmptid = HDF5Constants.H5I_INVALID_HID;
    891                datatypeClass = CLASS_ARRAY;
    892                try {
    893                    int ndims = H5.H5Tget_array_ndims(tid);
    894                    arrayDims = new long[ndims];
    895                    H5.H5Tget_array_dims(tid, arrayDims);
    896
    897                    tmptid = H5.H5Tget_super(tid);
    898                    int nativeBaseClass = H5.H5Tget_class(tmptid);
    899                    if (nativeBaseClass == HDF5Constants.H5T_REFERENCE)
    900                        baseType = new H5ReferenceType(this.fileFormat, 1, tmptid);
    901                    else
    902                        baseType = new H5Datatype(this.fileFormat, tmptid, this);
    903                    if (baseType == null) {
    904                        log.debug("fromNative(): ARRAY datatype has null base type");
    905                        throw new Exception("Datatype (ARRAY) has no base datatype");
    906                    }
    907
    908                    datatypeSign = baseType.getDatatypeSign();
    909                }
    910                catch (Exception ex) {
    911                    log.debug("fromNative(): array type failure: ", ex);
    912                }
    913                finally {
    914                    close(tmptid);
    915                }
    916            }
    917            else if (nativeClass == HDF5Constants.H5T_COMPOUND) {
    918                datatypeClass = CLASS_COMPOUND;
    919
    920                try {
    921                    int nMembers = H5.H5Tget_nmembers(tid);
    922                    compoundMemberNames = new Vector<>(nMembers);
    923                    compoundMemberTypes = new Vector<>(nMembers);
    924                    compoundMemberOffsets = new Vector<>(nMembers);
    925                    log.trace("fromNative(): compound type nMembers={} start", nMembers);
    926
    927                    for (int i = 0; i < nMembers; i++) {
    928                        String memberName = H5.H5Tget_member_name(tid, i);
    929                        log.trace("fromNative(): compound type [{}] name={} start", i, memberName);
    930                        long memberOffset = H5.H5Tget_member_offset(tid, i);
    931                        long memberID = HDF5Constants.H5I_INVALID_HID;
    932                        H5Datatype membertype = null;
    933                        try {
    934                            memberID = H5.H5Tget_member_type(tid, i);
    935                            int nativeMemberClass = H5.H5Tget_class(memberID);
    936                            if (nativeMemberClass == HDF5Constants.H5T_REFERENCE)
    937                                membertype = new H5ReferenceType(this.fileFormat, 1, memberID);
    938                            else
    939                                membertype = new H5Datatype(this.fileFormat, memberID, this);
    940                        }
    941                        catch (Exception ex1) {
    942                            log.debug("fromNative(): compound type failure: ", ex1);
    943                        }
    944                        finally {
    945                            close(memberID);
    946                        }
    947
    948                        compoundMemberNames.add(i, memberName);
    949                        compoundMemberOffsets.add(i, memberOffset);
    950                        compoundMemberTypes.add(i, membertype);
    951                    }
    952                }
    953                catch (HDF5LibraryException ex) {
    954                    log.debug("fromNative(): compound type failure: ", ex);
    955                }
    956            }
    957            else if (nativeClass == HDF5Constants.H5T_INTEGER) {
    958                datatypeClass = CLASS_INTEGER;
    959                try {
    960                    log.trace("fromNative(): integer type");
    961                    int tsign = H5.H5Tget_sign(tid);
    962                    datatypeSign = (tsign == HDF5Constants.H5T_SGN_NONE) ? SIGN_NONE : SIGN_2;
    963                }
    964                catch (Exception ex) {
    965                    log.debug("fromNative(): int type failure: ", ex);
    966                }
    967            }
    968            else if (nativeClass == HDF5Constants.H5T_FLOAT) {
    969                datatypeClass = CLASS_FLOAT;
    970                try {
    971                    nativeFPebias = H5.H5Tget_ebias_long(tid);
    972                }
    973                catch (Exception ex) {
    974                    log.debug("fromNative(): get_ebias failure: ", ex);
    975                }
    976                try {
    977                    long[] fields = new long[5];
    978                    H5.H5Tget_fields(tid, fields);
    979                    nativeFPspos = fields[0];
    980                    nativeFPepos = fields[1];
    981                    nativeFPesize = fields[2];
    982                    nativeFPmpos = fields[3];
    983                    nativeFPmsize = fields[4];
    984                }
    985                catch (Exception ex) {
    986                    log.debug("fromNative(): get_fields failure: ", ex);
    987                }
    988                try {
    989                    nativeFPnorm = H5.H5Tget_norm(tid);
    990                }
    991                catch (Exception ex) {
    992                    log.debug("fromNative(): get_norm failure: ", ex);
    993                }
    994                try {
    995                    nativeFPinpad = H5.H5Tget_inpad(tid);
    996                }
    997                catch (Exception ex) {
    998                    log.debug("fromNative(): get_inpad failure: ", ex);
    999                }
    1000            }
    1001            else if (isChar) {
    1002                datatypeClass = CLASS_CHAR;
    1003                datatypeSign = (isUchar) ? SIGN_NONE : SIGN_2;
    1004                log.trace("fromNative(): CLASS_CHAR:datatypeSign={}", datatypeSign);
    1005            }
    1006            else if (nativeClass == HDF5Constants.H5T_STRING) {
    1007                datatypeClass = CLASS_STRING;
    1008                try {
    1009                    isVLEN = H5.H5Tdetect_class(tid, HDF5Constants.H5T_VLEN)
    1010                            || isVariableStr;
    1011                    log.trace("fromNative(): H5T_STRING:var str type={}", isVLEN);
    1012                    nativeStrPad = H5.H5Tget_strpad(tid);
    1013                }
    1014                catch (Exception ex) {
    1015                    log.debug("fromNative(): var str type failure: ", ex);
    1016                }
    1017                try {
    1018                    nativeStrCSET = H5.H5Tget_cset(tid);
    1019                }
    1020                catch (Exception ex) {
    1021                    log.debug("fromNative(): H5T_STRING:get_cset failure: ", ex);
    1022                }
    1023                log.trace("fromNative(): H5T_STRING:nativeStrPad={}, nativeStrCSET={}", nativeStrPad, nativeStrCSET);
    1024            }
    1025            else if (nativeClass == HDF5Constants.H5T_REFERENCE) {
    1026                datatypeClass = CLASS_REFERENCE;
    1027                log.trace("fromNative(): reference type");
    1028                try {
    1029                    isStdRef = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF);
    1030                    log.trace("fromNative(): reference type is orig StdRef:{}", isStdRef);
    1031                    if (H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF))
    1032                        tsize = HDF5Constants.H5R_REF_BUF_SIZE;
    1033                }
    1034                catch (Exception ex) {
    1035                    log.debug("fromNative(): H5T_STD_REF: ", ex);
    1036                }
    1037                try {
    1038                    isRegRef = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG);
    1039                    log.trace("fromNative(): reference type isRegRef:{}", isRegRef);
    1040                    if (isRegRef)
    1041                        tsize = HDF5Constants.H5R_DSET_REG_REF_BUF_SIZE;
    1042                }
    1043                catch (Exception ex) {
    1044                    log.debug("fromNative(): H5T_STD_REF_DSETREG: ", ex);
    1045                }
    1046                try {
    1047                    isRefObj = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_OBJ);
    1048                    log.trace("fromNative(): reference type isRefObj:{}", isRefObj);
    1049                    if (isRefObj)
    1050                        tsize = HDF5Constants.H5R_OBJ_REF_BUF_SIZE;
    1051                }
    1052                catch (Exception ex) {
    1053                    log.debug("fromNative(): H5T_STD_REF_OBJ: ", ex);
    1054                }
    1055            }
    1056            else if (nativeClass == HDF5Constants.H5T_ENUM) {
    1057                datatypeClass = CLASS_ENUM;
    1058                long tmptid = HDF5Constants.H5I_INVALID_HID;
    1059                long basetid = HDF5Constants.H5I_INVALID_HID;
    1060                try {
    1061                    log.trace("fromNative(): enum type");
    1062                    basetid = H5.H5Tget_super(tid);
    1063                    tmptid = basetid;
    1064                    basetid = H5.H5Tget_native_type(tmptid);
    1065                    log.trace("fromNative(): enum type basetid={}", basetid);
    1066                    if (basetid >= 0) {
    1067                        baseType = new H5Datatype(this.fileFormat, tmptid, this);
    1068                        datatypeSign = baseType.getDatatypeSign();
    1069                    }
    1070                }
    1071                catch (Exception ex) {
    1072                    log.debug("fromNative(): enum type failure: ", ex);
    1073                }
    1074                finally {
    1075                    close(tmptid);
    1076                    close(basetid);
    1077                }
    1078                try {
    1079                    int enumMemberCount = H5.H5Tget_nmembers(tid);
    1080                    String name = null;
    1081                    String enumStr = null;
    1082                    byte[] val = new byte[(int) tsize];
    1083                    enumMembers = new HashMap<>();
    1084                    for (int i = 0; i < enumMemberCount; i++) {
    1085                        name = H5.H5Tget_member_name(tid, i);
    1086                        H5.H5Tget_member_value(tid, i, val);
    1087                        switch ((int) H5.H5Tget_size(tid)) {
    1088                        case 1:
    1089                            enumStr = Byte.toString((HDFNativeData.byteToByte(val[0]))[0]);
    1090                            break;
    1091                        case 2:
    1092                            enumStr = Short.toString((HDFNativeData.byteToShort(val))[0]);
    1093                            break;
    1094                        case 4:
    1095                            enumStr = Integer.toString((HDFNativeData.byteToInt(val))[0]);
    1096                            break;
    1097                        case 8:
    1098                            enumStr = Long.toString((HDFNativeData.byteToLong(val))[0]);
    1099                            break;
    1100                        default:
    1101                            enumStr = "-1";
    1102                            break;
    1103                        }
    1104                        enumMembers.put(enumStr, name);
    1105                    }
    1106                }
    1107                catch (Exception ex) {
    1108                    log.debug("fromNative(): enum type failure: ", ex);
    1109                }
    1110            }
    1111            else if (nativeClass == HDF5Constants.H5T_VLEN) {
    1112                long tmptid = HDF5Constants.H5I_INVALID_HID;
    1113                datatypeClass = CLASS_VLEN;
    1114                isVLEN = true;
    1115                try {
    1116                    log.trace("fromNative(): vlen type");
    1117                    tmptid = H5.H5Tget_super(tid);
    1118                    int nativeBaseClass = H5.H5Tget_class(tmptid);
    1119                    if (nativeBaseClass == HDF5Constants.H5T_REFERENCE)
    1120                        baseType = new H5ReferenceType(this.fileFormat, 1, tmptid);
    1121                    else
    1122                        baseType = new H5Datatype(this.fileFormat, tmptid, this);
    1123                    if (baseType == null) {
    1124                        log.debug("fromNative(): VLEN datatype has null base type");
    1125                        throw new Exception("Datatype (VLEN) has no base datatype");
    1126                    }
    1127
    1128                    datatypeSign = baseType.getDatatypeSign();
    1129                }
    1130                catch (Exception ex) {
    1131                    log.debug("fromNative(): vlen type failure: ", ex);
    1132                }
    1133                finally {
    1134                    close(tmptid);
    1135                }
    1136            }
    1137            else if (nativeClass == HDF5Constants.H5T_BITFIELD) {
    1138                datatypeClass = CLASS_BITFIELD;
    1139            }
    1140            else if (nativeClass == HDF5Constants.H5T_OPAQUE) {
    1141                datatypeClass = CLASS_OPAQUE;
    1142
    1143                try {
    1144                    opaqueTag = H5.H5Tget_tag(tid);
    1145                }
    1146                catch (Exception ex) {
    1147                    log.debug("fromNative(): opaque type tag retrieval failed: ", ex);
    1148                    opaqueTag = null;
    1149                }
    1150            }
    1151            else {
    1152                log.debug("fromNative(): datatypeClass is unknown");
    1153            }
    1154
    1155            datatypeSize = (isVLEN
    1156                    && !isVariableStr) ? HDF5Constants.H5T_VL_T : tsize;
    1157        }
    1158        if (datatypeSize == NATIVE)
    1159            datatypeNATIVE = true;
    1160        else
    1161            datatypeNATIVE = false;
    1162        log.trace("fromNative(): datatypeClass={} baseType={} datatypeSize={}", datatypeClass, baseType, datatypeSize);
    1163    }
    1164
    1165    /**
    1166     * @param tid
    1167     *            the datatype identification disk.
    1168     * @return the memory datatype identifier if successful, and negative otherwise.
    1169     */
    1170    public static long toNative(long tid) {
    1171        // data type information
    1172        log.trace("toNative(): tid={} start", tid);
    1173        long nativeID = HDF5Constants.H5I_INVALID_HID;
    1174
    1175        try {
    1176            nativeID = H5.H5Tget_native_type(tid);
    1177        }
    1178        catch (Exception ex) {
    1179            log.debug("toNative(): H5Tget_native_type(tid {}) failure: ", tid, ex);
    1180        }
    1181
    1182        try {
    1183            if (H5.H5Tis_variable_str(tid))
    1184                H5.H5Tset_size(nativeID, HDF5Constants.H5T_VARIABLE);
    1185        }
    1186        catch (Exception ex) {
    1187            log.debug("toNative(): var str type size failure: ", ex);
    1188        }
    1189
    1190        return nativeID;
    1191    }
    1192
    1193    /*
    1194     * (non-Javadoc)
    1195     * @see hdf.object.Datatype#createNative()
    1196     */
    1197    @SuppressWarnings("rawtypes")
    1198    @Override
    1199    public long createNative() {
    1200        long tid = HDF5Constants.H5I_INVALID_HID;
    1201        long tmptid = HDF5Constants.H5I_INVALID_HID;
    1202
    1203        String the_path = getFullName();
    1204        // isNamed == true should have non-null fileFormat
    1205        if (isNamed()) {
    1206            try {
    1207                tid = H5.H5Topen(getFID(), the_path, HDF5Constants.H5P_DEFAULT);
    1208            }
    1209            catch (Exception ex) {
    1210                log.debug("createNative(): name {} H5Topen failure: ", the_path, ex);
    1211            }
    1212        }
    1213        else
    1214            log.debug("createNative(): isNamed={} and named path={}", isNamed(), the_path);
    1215
    1216        if (tid >= 0)
    1217            return tid;
    1218
    1219        log.trace("createNative(): datatypeClass={} datatypeSize={} baseType={}", datatypeClass, datatypeSize,
    1220                baseType);
    1221
    1222        switch (datatypeClass) {
    1223        case CLASS_ARRAY:
    1224            try {
    1225                if (baseType == null) {
    1226                    log.debug("createNative(): CLASS_ARRAY base type is NULL");
    1227                    break;
    1228                }
    1229
    1230                if ((tmptid = baseType.createNative()) < 0) {
    1231                    log.debug("createNative(): failed to create native datatype for ARRAY base datatype");
    1232                    break;
    1233                }
    1234
    1235                tid = H5.H5Tarray_create(tmptid, arrayDims.length, arrayDims);
    1236            }
    1237            catch (Exception ex) {
    1238                log.debug("createNative(): native array datatype creation failed: ", ex);
    1239                if (tid >= 0)
    1240                    close(tid);
    1241                tid = HDF5Constants.H5I_INVALID_HID;
    1242            }
    1243            finally {
    1244                close(tmptid);
    1245            }
    1246
    1247            break;
    1248        case CLASS_COMPOUND:
    1249            try {
    1250                tid = H5.H5Tcreate(CLASS_COMPOUND, datatypeSize);
    1251
    1252                for (int i = 0; i < compoundMemberTypes.size(); i++) {
    1253                    H5Datatype memberType = null;
    1254                    String memberName = null;
    1255                    long memberOffset = -1;
    1256
    1257                    try {
    1258                        memberType = (H5Datatype) compoundMemberTypes.get(i);
    1259                    }
    1260                    catch (Exception ex) {
    1261                        log.debug("createNative(): get compound member[{}] type failure: ", i, ex);
    1262                        memberType = null;
    1263                    }
    1264
    1265                    try {
    1266                        memberName = compoundMemberNames.get(i);
    1267                    }
    1268                    catch (Exception ex) {
    1269                        log.debug("createNative(): get compound member[{}] name failure: ", i, ex);
    1270                        memberName = null;
    1271                    }
    1272
    1273                    try {
    1274                        memberOffset = compoundMemberOffsets.get(i);
    1275                    }
    1276                    catch (Exception ex) {
    1277                        log.debug("createNative(): get compound member[{}] offset failure: ", i, ex);
    1278                        memberOffset = -1;
    1279                    }
    1280
    1281                    long memberID = HDF5Constants.H5I_INVALID_HID;
    1282                    try {
    1283                        memberID = memberType.createNative();
    1284                        log.trace("createNative(): {} member[{}] with offset={} ID={}: ", memberName, i, memberOffset,
    1285                                memberID);
    1286
    1287                        H5.H5Tinsert(tid, memberName, memberOffset, memberID);
    1288                    }
    1289                    catch (Exception ex) {
    1290                        log.debug("createNative(): compound type member[{}] insertion failure: ", i, ex);
    1291                    }
    1292                    finally {
    1293                        close(memberID);
    1294                    }
    1295                }
    1296            }
    1297            catch (Exception ex) {
    1298                log.debug("createNative(): native compound datatype creation failed: ", ex);
    1299                if (tid >= 0)
    1300                    close(tid);
    1301                tid = HDF5Constants.H5I_INVALID_HID;
    1302            }
    1303            break;
    1304        case CLASS_INTEGER:
    1305            log.trace("createNative(): CLASS_INT of size {}", datatypeSize);
    1306
    1307            try {
    1308                switch ((int) datatypeSize) {
    1309                case 1:
    1310                    log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT8");
    1311                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8);
    1312                    break;
    1313                case 2:
    1314                    log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT16");
    1315                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT16);
    1316                    break;
    1317                case 4:
    1318                    log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT32");
    1319                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32);
    1320                    break;
    1321                case 8:
    1322                    log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT64");
    1323                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT64);
    1324                    break;
    1325                default:
    1326                    if (datatypeSize == NATIVE) {
    1327                        datatypeNATIVE = true;
    1328                        log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT");
    1329                        tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT);
    1330                        datatypeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT);
    1331                    }
    1332                    else {
    1333                        datatypeNATIVE = false;
    1334                        /* Custom sized integer */
    1335                        tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8);
    1336                        H5.H5Tset_size(tid, datatypeSize);
    1337                        H5.H5Tset_precision(tid, 8 * datatypeSize);
    1338                    }
    1339                    break;
    1340                }
    1341
    1342                if (datatypeOrder == Datatype.ORDER_BE) {
    1343                    log.trace("createNative(): CLASS_INT order is H5T_ORDER_BE");
    1344                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
    1345                }
    1346                else if (datatypeOrder == Datatype.ORDER_LE) {
    1347                    log.trace("createNative(): CLASS_INT order is H5T_ORDER_LE");
    1348                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
    1349                }
    1350
    1351                if (datatypeSign == Datatype.SIGN_NONE) {
    1352                    log.trace("createNative(): CLASS_INT sign is H5T_SGN_NONE");
    1353                    H5.H5Tset_sign(tid, HDF5Constants.H5T_SGN_NONE);
    1354                }
    1355            }
    1356            catch (Exception ex) {
    1357                log.debug("createNative(): native integer datatype creation failed: ", ex);
    1358                if (tid >= 0)
    1359                    close(tid);
    1360                tid = -1;
    1361            }
    1362
    1363            break;
    1364        case CLASS_ENUM:
    1365            log.trace("createNative(): CLASS_ENUM");
    1366            try {
    1367                if (baseType != null) {
    1368                    if ((tmptid = baseType.createNative()) < 0) {
    1369                        log.debug("createNative(): failed to create native type for ENUM base datatype");
    1370                        break;
    1371                    }
    1372
    1373                    tid = H5.H5Tenum_create(tmptid);
    1374                }
    1375                else {
    1376                    if (datatypeSize == NATIVE) {
    1377                        datatypeNATIVE = true;
    1378                        datatypeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT);
    1379                    }
    1380                    else
    1381                        datatypeNATIVE = false;
    1382
    1383                    tid = H5.H5Tcreate(HDF5Constants.H5T_ENUM, datatypeSize);
    1384                }
    1385
    1386                if (datatypeOrder == Datatype.ORDER_BE) {
    1387                    log.trace("createNative(): CLASS_ENUM order is H5T_ORDER_BE");
    1388                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
    1389                }
    1390                else if (datatypeOrder == Datatype.ORDER_LE) {
    1391                    log.trace("createNative(): CLASS_ENUM order is H5T_ORDER_LE");
    1392                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
    1393                }
    1394
    1395                if (datatypeSign == Datatype.SIGN_NONE) {
    1396                    log.trace("createNative(): CLASS_ENUM sign is H5T_SGN_NONE");
    1397                    H5.H5Tset_sign(tid, HDF5Constants.H5T_SGN_NONE);
    1398                }
    1399            }
    1400            catch (Exception ex) {
    1401                log.debug("createNative(): native enum datatype creation failed: ", ex);
    1402                if (tid >= 0)
    1403                    close(tid);
    1404                tid = HDF5Constants.H5I_INVALID_HID;
    1405            }
    1406            finally {
    1407                close(tmptid);
    1408            }
    1409
    1410            break;
    1411        case CLASS_FLOAT:
    1412            try {
    1413                if (datatypeSize > 8)
    1414                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_LDOUBLE);
    1415                else
    1416                    tid = H5.H5Tcopy(
    1417                            (datatypeSize == 8) ? HDF5Constants.H5T_NATIVE_DOUBLE : HDF5Constants.H5T_NATIVE_FLOAT);
    1418
    1419                if (datatypeOrder == Datatype.ORDER_BE) {
    1420                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
    1421                }
    1422                else if (datatypeOrder == Datatype.ORDER_LE) {
    1423                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
    1424                }
    1425
    1426                if (nativeFPebias > 0) {
    1427                    H5.H5Tset_ebias(tid, nativeFPebias);
    1428                }
    1429
    1430                if (nativeFPnorm >= 0) {
    1431                    H5.H5Tset_norm(tid, nativeFPnorm);
    1432                }
    1433
    1434                if (nativeFPinpad >= 0) {
    1435                    H5.H5Tset_inpad(tid, nativeFPinpad);
    1436                }
    1437
    1438                if ((nativeFPesize >= 0)
    1439                        && (nativeFPmsize >= 0)) {
    1440                    H5.H5Tset_fields(tid, nativeFPspos, nativeFPmpos, nativeFPesize, nativeFPmpos, nativeFPmsize);
    1441                }
    1442            }
    1443            catch (Exception ex) {
    1444                log.debug("createNative(): native floating-point datatype creation failed: ", ex);
    1445                if (tid >= 0)
    1446                    close(tid);
    1447                tid = HDF5Constants.H5I_INVALID_HID;
    1448            }
    1449
    1450            break;
    1451        case CLASS_CHAR:
    1452            try {
    1453                tid = H5.H5Tcopy((datatypeSign == Datatype.SIGN_NONE) ? HDF5Constants.H5T_NATIVE_UCHAR
    1454                        : HDF5Constants.H5T_NATIVE_CHAR);
    1455            }
    1456            catch (Exception ex) {
    1457                log.debug("createNative(): native character datatype creation failed: ", ex);
    1458                if (tid >= 0)
    1459                    close(tid);
    1460                tid = HDF5Constants.H5I_INVALID_HID;
    1461            }
    1462
    1463            break;
    1464        case CLASS_STRING:
    1465            try {
    1466                tid = H5.H5Tcopy(HDF5Constants.H5T_C_S1);
    1467
    1468                H5.H5Tset_size(tid, (isVLEN
    1469                        || datatypeSize < 0) ? HDF5Constants.H5T_VARIABLE : datatypeSize);
    1470
    1471                log.trace("createNative(): isVlenStr={} nativeStrPad={} nativeStrCSET={}", isVLEN, nativeStrPad,
    1472                        nativeStrCSET);
    1473
    1474                H5.H5Tset_strpad(tid, (nativeStrPad >= 0) ? nativeStrPad : HDF5Constants.H5T_STR_NULLTERM);
    1475
    1476                if (nativeStrCSET >= 0) {
    1477                    H5.H5Tset_cset(tid, nativeStrCSET);
    1478                }
    1479            }
    1480            catch (Exception ex) {
    1481                log.debug("createNative(): native string datatype creation failed: ", ex);
    1482                if (tid >= 0)
    1483                    close(tid);
    1484                tid = HDF5Constants.H5I_INVALID_HID;
    1485            }
    1486
    1487            break;
    1488        case CLASS_REFERENCE:
    1489            try {
    1490                long objRefTypeSize = H5.H5Tget_size(HDF5Constants.H5T_STD_REF_OBJ);
    1491                long dsetRefTypeSize = H5.H5Tget_size(HDF5Constants.H5T_STD_REF_DSETREG);
    1492                // use datatypeSize as which type to copy
    1493                log.debug("createNative(): datatypeSize:{} ", datatypeSize);
    1494                if (datatypeSize < 0
    1495                        || datatypeSize > dsetRefTypeSize) {
    1496                    tid = H5.H5Tcopy(HDF5Constants.H5T_STD_REF);
    1497                    log.debug("createNative(): HDF5Constants.H5T_STD_REF");
    1498                }
    1499                else if (datatypeSize > objRefTypeSize) {
    1500                    tid = H5.H5Tcopy(HDF5Constants.H5T_STD_REF_DSETREG);
    1501                    log.debug("createNative(): HDF5Constants.H5T_STD_REF_DSETREG");
    1502                }
    1503                else {
    1504                    tid = H5.H5Tcopy(HDF5Constants.H5T_STD_REF_OBJ);
    1505                    log.debug("createNative(): HDF5Constants.H5T_STD_REF_OBJ");
    1506                }
    1507            }
    1508            catch (Exception ex) {
    1509                log.debug("createNative(): native reference datatype creation failed: ", ex);
    1510                if (tid >= 0)
    1511                    close(tid);
    1512                tid = HDF5Constants.H5I_INVALID_HID;
    1513            }
    1514
    1515            break;
    1516        case CLASS_VLEN:
    1517            try {
    1518                if (baseType == null) {
    1519                    log.debug("createNative(): CLASS_VLEN base type is NULL");
    1520                    break;
    1521                }
    1522
    1523                if ((tmptid = baseType.createNative()) < 0) {
    1524                    log.debug("createNative(): failed to create native datatype for VLEN base datatype");
    1525                    break;
    1526                }
    1527
    1528                tid = H5.H5Tvlen_create(tmptid);
    1529            }
    1530            catch (Exception ex) {
    1531                log.debug("createNative(): native variable-length datatype creation failed: ", ex);
    1532                if (tid >= 0)
    1533                    close(tid);
    1534                tid = HDF5Constants.H5I_INVALID_HID;
    1535            }
    1536            finally {
    1537                close(tmptid);
    1538            }
    1539
    1540            break;
    1541        case CLASS_BITFIELD:
    1542            log.trace("createNative(): CLASS_BITFIELD size is {}", datatypeSize);
    1543
    1544            try {
    1545                switch ((int) datatypeSize) {
    1546                case 1:
    1547                    log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B8");
    1548                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B8);
    1549                    break;
    1550                case 2:
    1551                    log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B16");
    1552                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B16);
    1553                    break;
    1554                case 4:
    1555                    log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B32");
    1556                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B32);
    1557                    break;
    1558                case 8:
    1559                    log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B64");
    1560                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B64);
    1561                    break;
    1562                default:
    1563                    if (datatypeSize == NATIVE) {
    1564                        datatypeNATIVE = true;
    1565                        datatypeSize = 1;
    1566                    }
    1567                    else
    1568                        datatypeNATIVE = false;
    1569
    1570                    /* Custom sized bitfield */
    1571                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B8);
    1572                    H5.H5Tset_size(tid, datatypeSize);
    1573                    H5.H5Tset_precision(tid, 8 * datatypeSize);
    1574
    1575                    break;
    1576                }
    1577
    1578                if (datatypeOrder == Datatype.ORDER_BE) {
    1579                    log.trace("createNative(): CLASS_BITFIELD order is H5T_ORDER_BE");
    1580                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
    1581                }
    1582                else if (datatypeOrder == Datatype.ORDER_LE) {
    1583                    log.trace("createNative(): CLASS_BITFIELD order is H5T_ORDER_LE");
    1584                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
    1585                }
    1586            }
    1587            catch (Exception ex) {
    1588                log.debug("createNative(): native bitfield datatype creation failed: ", ex);
    1589                if (tid >= 0)
    1590                    close(tid);
    1591                tid = HDF5Constants.H5I_INVALID_HID;
    1592            }
    1593
    1594            break;
    1595        case CLASS_OPAQUE:
    1596            log.trace("createNative(): CLASS_OPAQUE is {}-byte H5T_OPAQUE", datatypeSize);
    1597
    1598            try {
    1599                if (datatypeSize == NATIVE) {
    1600                    datatypeNATIVE = true;
    1601                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_OPAQUE);
    1602                    datatypeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_OPAQUE);
    1603                }
    1604                else {
    1605                    datatypeNATIVE = false;
    1606                    tid = H5.H5Tcreate(HDF5Constants.H5T_OPAQUE, datatypeSize);
    1607                }
    1608
    1609                if (opaqueTag != null) {
    1610                    H5.H5Tset_tag(tid, opaqueTag);
    1611                }
    1612            }
    1613            catch (Exception ex) {
    1614                log.debug("createNative(): native opaque datatype creation failed: ", ex);
    1615                if (tid >= 0)
    1616                    close(tid);
    1617                tid = HDF5Constants.H5I_INVALID_HID;
    1618            }
    1619
    1620            break;
    1621        default:
    1622            log.debug("createNative(): Unknown class");
    1623            break;
    1624        } // (tclass)
    1625
    1626        // set up enum members
    1627        if ((datatypeClass == CLASS_ENUM)
    1628                && (enumMembers != null)) {
    1629            log.trace("createNative(): set up enum members");
    1630            try {
    1631                String memstr;
    1632                String memname;
    1633                byte[] memval = null;
    1634
    1635                Iterator entries = enumMembers.entrySet().iterator();
    1636                while (entries.hasNext()) {
    1637                    Entry thisEntry = (Entry) entries.next();
    1638                    memstr = (String) thisEntry.getKey();
    1639                    memname = (String) thisEntry.getValue();
    1640
    1641                    if (datatypeSize == 1) {
    1642                        log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT8");
    1643                        Byte tval = Byte.parseByte(memstr);
    1644                        memval = HDFNativeData.byteToByte(tval);
    1645                    }
    1646                    else if (datatypeSize == 2) {
    1647                        log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT16");
    1648                        Short tval = Short.parseShort(memstr);
    1649                        memval = HDFNativeData.shortToByte(tval);
    1650                    }
    1651                    else if (datatypeSize == 4) {
    1652                        log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT32");
    1653                        Integer tval = Integer.parseInt(memstr);
    1654                        memval = HDFNativeData.intToByte(tval);
    1655                    }
    1656                    else if (datatypeSize == 8) {
    1657                        log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT64");
    1658                        Long tval = Long.parseLong(memstr);
    1659                        memval = HDFNativeData.longToByte(tval);
    1660                    }
    1661                    else {
    1662                        log.debug("createNative(): enum datatypeSize incorrect");
    1663                    }
    1664                    log.trace("createNative(): H5Tenum_insert {} {}", memname, memval);
    1665                    H5.H5Tenum_insert(tid, memname, memval);
    1666                }
    1667            }
    1668            catch (Exception ex) {
    1669                log.debug("createNative(): set up enum members failure: ", ex);
    1670            }
    1671        } // (datatypeClass == CLASS_ENUM)
    1672
    1673        try {
    1674            tmptid = tid;
    1675            tid = H5.H5Tget_native_type(tmptid);
    1676        }
    1677        catch (HDF5Exception ex) {
    1678            log.debug("createNative(): H5Tget_native_type({}) failure: ", tmptid, ex);
    1679        }
    1680        finally {
    1681            close(tmptid);
    1682        }
    1683
    1684        return tid;
    1685    }
    1686
    1687    /**
    1688     * Allocates a one-dimensional array of byte, short, int, long, float, double, or String to store data in memory.
    1689     * For example,
    1690     *
    1691     * <pre>
    1692     * long tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32);
    1693     * int[] data = (int[]) H5Datatype.allocateArray(datatype, 100);
    1694     * </pre>
    1695     *
    1696     * returns a 32-bit integer array of size 100.
    1697     *
    1698     * @param dtype
    1699     *                  the type.
    1700     * @param numPoints
    1701     *                  the total number of data points of the array.
    1702     * @return the array object if successful; otherwise, return null.
    1703     * @throws OutOfMemoryError
    1704     *                          If there is a failure.
    1705     */
    1706    public static final Object allocateArray(final H5Datatype dtype, int numPoints)
    1707            throws OutOfMemoryError {
    1708        log.trace("allocateArray(): start: numPoints={}", numPoints);
    1709
    1710        Object data = null;
    1711        H5Datatype baseType = (H5Datatype) dtype.getDatatypeBase();
    1712        int typeClass = dtype.getDatatypeClass();
    1713        long typeSize = dtype.getDatatypeSize();
    1714
    1715        if (numPoints < 0) {
    1716            log.debug("allocateArray(): numPoints < 0");
    1717            return null;
    1718        }
    1719
    1720        // Scalar members have dimensionality zero, i.e. size =0
    1721        // what can we do about it, set the size to 1
    1722        if (numPoints == 0)
    1723            numPoints = 1;
    1724
    1725        log.trace("allocateArray(): tclass={} : tsize={}", typeClass, typeSize);
    1726
    1727        if (dtype.isVarStr()) {
    1728            log.trace("allocateArray(): is_variable_str={}", dtype.isVarStr());
    1729
    1730            data = new String[numPoints];
    1731            for (int i = 0; i < numPoints; i++)
    1732                ((String[]) data)[i] = "";
    1733        }
    1734        else if (typeClass == HDF5Constants.H5T_INTEGER) {
    1735            log.trace("allocateArray(): class H5T_INTEGER");
    1736            if (typeSize == NATIVE)
    1737                typeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT);
    1738
    1739            switch ((int) typeSize) {
    1740            case 1:
    1741                data = new byte[numPoints];
    1742                break;
    1743            case 2:
    1744                data = new short[numPoints];
    1745                break;
    1746            case 4:
    1747                data = new int[numPoints];
    1748                break;
    1749            case 8:
    1750                data = new long[numPoints];
    1751                break;
    1752            default:
    1753                break;
    1754            }
    1755        }
    1756        else if (typeClass == HDF5Constants.H5T_ENUM) {
    1757            log.trace("allocateArray(): class H5T_ENUM");
    1758
    1759            if (baseType != null)
    1760                data = H5Datatype.allocateArray(baseType, numPoints);
    1761            else {
    1762                if (typeSize == NATIVE)
    1763                    typeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT);
    1764                data = new byte[(int) (numPoints * typeSize)];
    1765            }
    1766        }
    1767        else if (typeClass == HDF5Constants.H5T_COMPOUND) {
    1768            log.trace("allocateArray(): class H5T_COMPOUND");
    1769
    1770            data = new ArrayList<>(dtype.getCompoundMemberTypes().size());
    1771        }
    1772        else if (typeClass == HDF5Constants.H5T_FLOAT) {
    1773            log.trace("allocateArray(): class H5T_FLOAT");
    1774            if (typeSize == NATIVE)
    1775                typeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_FLOAT);
    1776
    1777            switch ((int) typeSize) {
    1778            case 4:
    1779                data = new float[numPoints];
    1780                break;
    1781            case 8:
    1782                data = new double[numPoints];
    1783                break;
    1784            case 16:
    1785                data = new byte[numPoints * 16];
    1786                break;
    1787            default:
    1788                break;
    1789            }
    1790        }
    1791        else if ((typeClass == HDF5Constants.H5T_STRING)
    1792                || (typeClass == HDF5Constants.H5T_REFERENCE)) {
    1793            log.trace("allocateArray(): class H5T_STRING || H5T_REFERENCE");
    1794
    1795            data = new byte[(int) (numPoints * typeSize)];
    1796        }
    1797        else if (dtype.isVLEN()) {
    1798            log.trace("allocateArray(): isVLEN");
    1799
    1800            data = new ArrayList[numPoints];
    1801            for (int j = 0; j < numPoints; j++)
    1802                ((ArrayList[])data)[j] = new ArrayList<byte[]>();
    1803                // if (baseType != null)
    1804                // ((ArrayList<>)data).add(H5Datatype.allocateArray(baseType, numPoints));
    1805        }
    1806        else if (typeClass == HDF5Constants.H5T_ARRAY) {
    1807            log.trace("allocateArray(): class H5T_ARRAY");
    1808
    1809            try {
    1810                log.trace("allocateArray(): ArrayRank={}", dtype.getArrayDims().length);
    1811
    1812                // Use the base datatype to define the array
    1813                long[] arrayDims = dtype.getArrayDims();
    1814                int asize = numPoints;
    1815                for (int j = 0; j < arrayDims.length; j++) {
    1816                    log.trace("allocateArray(): Array dims[{}]={}", j, arrayDims[j]);
    1817
    1818                    asize *= arrayDims[j];
    1819                }
    1820
    1821                if (baseType != null)
    1822                    data = H5Datatype.allocateArray(baseType, asize);
    1823            }
    1824            catch (Exception ex) {
    1825                log.debug("allocateArray(): H5T_ARRAY class failure: ", ex);
    1826            }
    1827        }
    1828        else if ((typeClass == HDF5Constants.H5T_OPAQUE)
    1829                || (typeClass == HDF5Constants.H5T_BITFIELD)) {
    1830            log.trace("allocateArray(): class H5T_OPAQUE || H5T_BITFIELD");
    1831            if (typeSize == NATIVE)
    1832                typeSize = H5.H5Tget_size(typeClass);
    1833
    1834            data = new byte[(int) (numPoints * typeSize)];
    1835        }
    1836        else {
    1837            log.debug("allocateArray(): class ???? ({})", typeClass);
    1838
    1839            data = null;
    1840        }
    1841
    1842        return data;
    1843    }
    1844
    1845    /**
    1846     * Returns the size (in bytes) of a given datatype identifier. It basically just calls H5Tget_size(tid).
    1847     *
    1848     * @param tid
    1849     *            The datatype identifier.
    1850     * @return The size of the datatype in bytes.
    1851     * @see hdf.hdf5lib.H5#H5Tget_size(long)
    1852     */
    1853    public static final long getDatatypeSize(long tid) {
    1854        // data type information
    1855        long tsize = -1;
    1856
    1857        try {
    1858            tsize = H5.H5Tget_size(tid);
    1859        }
    1860        catch (Exception ex) {
    1861            tsize = -1;
    1862        }
    1863
    1864        return tsize;
    1865    }
    1866
    1867    /*
    1868     * (non-Javadoc)
    1869     * @see hdf.object.Datatype#getDescription()
    1870     */
    1871    @Override
    1872    public String getDescription() {
    1873        log.trace("getDescription(): start - isNamed={}", isNamed());
    1874
    1875        if (datatypeDescription != null)
    1876            return datatypeDescription;
    1877
    1878        StringBuilder description = new StringBuilder();
    1879        long tid = HDF5Constants.H5I_INVALID_HID;
    1880
    1881        switch (datatypeClass) {
    1882        case CLASS_CHAR:
    1883            log.trace("getDescription(): Char");
    1884            description.append("8-bit ").append(isUnsigned() ? "unsigned " : "").append("integer");
    1885            break;
    1886        case CLASS_INTEGER:
    1887            log.trace("getDescription(): Int [{}]", datatypeNATIVE);
    1888            if (datatypeNATIVE)
    1889                description.append("native ").append(isUnsigned() ? "unsigned " : "").append("integer");
    1890            else
    1891                description.append(String.valueOf(datatypeSize * 8)).append("-bit ")
    1892                .append(isUnsigned() ? "unsigned " : "").append("integer");
    1893            break;
    1894        case CLASS_FLOAT:
    1895            log.trace("getDescription(): Float");
    1896            if (datatypeNATIVE)
    1897                description.append("native floating-point");
    1898            else
    1899                description.append(String.valueOf(datatypeSize * 8)).append("-bit floating-point");
    1900            break;
    1901        case CLASS_STRING:
    1902            log.trace("getDescription(): String");
    1903            description.append("String, length = ").append(isVarStr() ? "variable" : datatypeSize);
    1904
    1905            try {
    1906                tid = createNative();
    1907                if (tid >= 0) {
    1908                    String strPadType;
    1909                    String strCSETType;
    1910                    int strPad = H5.H5Tget_strpad(tid);
    1911                    int strCSET = H5.H5Tget_cset(tid);
    1912
    1913                    if (strPad == HDF5Constants.H5T_STR_NULLTERM)
    1914                        strPadType = "H5T_STR_NULLTERM";
    1915                    else if (strPad == HDF5Constants.H5T_STR_NULLPAD)
    1916                        strPadType = "H5T_STR_NULLPAD";
    1917                    else if (strPad == HDF5Constants.H5T_STR_SPACEPAD)
    1918                        strPadType = "H5T_STR_SPACEPAD";
    1919                    else
    1920                        strPadType = null;
    1921
    1922                    if (strPadType != null)
    1923                        description.append(", padding = ").append(strPadType);
    1924
    1925                    if (strCSET == HDF5Constants.H5T_CSET_ASCII)
    1926                        strCSETType = "H5T_CSET_ASCII";
    1927                    else if (strCSET == HDF5Constants.H5T_CSET_UTF8)
    1928                        strCSETType = "H5T_CSET_UTF8";
    1929                    else
    1930                        strCSETType = null;
    1931
    1932                    if (strCSETType != null)
    1933                        description.append(", cset = ").append(strCSETType);
    1934                }
    1935                else {
    1936                    log.debug("createNative() failure");
    1937                }
    1938            }
    1939            catch (Exception ex) {
    1940                log.debug("H5Tget_strpad failure: ", ex);
    1941            }
    1942            finally {
    1943                close(tid);
    1944            }
    1945            break;
    1946        case CLASS_BITFIELD:
    1947            log.trace("getDescription(): Bit");
    1948            if (datatypeNATIVE)
    1949                description.append("native bitfield");
    1950            else
    1951                description.append(String.valueOf(datatypeSize * 8)).append("-bit bitfield");
    1952            break;
    1953        case CLASS_OPAQUE:
    1954            log.trace("getDescription(): Opaque");
    1955            if (datatypeNATIVE)
    1956                description.append("native Opaque");
    1957            else
    1958                description.append(String.valueOf(datatypeSize)).append("-byte Opaque");
    1959
    1960            if (opaqueTag != null) {
    1961                description.append(", tag = ").append(opaqueTag);
    1962            }
    1963
    1964            break;
    1965        case CLASS_COMPOUND:
    1966            log.trace("getDescription(): Compound");
    1967            description.append("Compound");
    1968
    1969            if ((compoundMemberTypes != null)
    1970                    && !compoundMemberTypes.isEmpty()) {
    1971                Iterator<String> memberNames = null;
    1972                Iterator<Datatype> memberTypes = compoundMemberTypes.iterator();
    1973
    1974                if (compoundMemberNames != null)
    1975                    memberNames = compoundMemberNames.iterator();
    1976
    1977                description.append(" {");
    1978
    1979                while (memberTypes.hasNext()) {
    1980                    if (memberNames != null
    1981                            && memberNames.hasNext()) {
    1982                        description.append(memberNames.next()).append(" = ");
    1983                    }
    1984
    1985                    description.append(memberTypes.next().getDescription());
    1986
    1987                    if (memberTypes.hasNext())
    1988                        description.append(", ");
    1989                }
    1990
    1991                description.append("}");
    1992            }
    1993
    1994            break;
    1995        case CLASS_REFERENCE:
    1996            log.trace("getDescription(): Ref");
    1997            description.append("Reference");
    1998
    1999            try {
    2000                boolean isRegionType = false;
    2001
    2002                tid = createNative();
    2003                if (tid >= 0) {
    2004                    if (!H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF)) {
    2005                        isRegionType = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG);
    2006
    2007                        description.setLength(0);
    2008                        if (isRegionType) {
    2009                            description.append("Dataset region reference");
    2010                        }
    2011                        else {
    2012                            description.append("Object reference");
    2013                        }
    2014                    }
    2015                }
    2016            }
    2017            catch (Exception ex) {
    2018                log.debug("H5.H5Tequal failure: ", ex);
    2019            }
    2020            finally {
    2021                close(tid);
    2022            }
    2023
    2024            break;
    2025        case CLASS_ENUM:
    2026            log.trace("getDescription(): Enum");
    2027            if (datatypeNATIVE)
    2028                description.append("native enum");
    2029            else
    2030                description.append(String.valueOf(datatypeSize * 8)).append("-bit enum");
    2031
    2032            String members = getEnumMembersAsString();
    2033            if (members != null)
    2034                description.append(" (").append(members).append(")");
    2035
    2036            break;
    2037        case CLASS_VLEN:
    2038            log.trace("getDescription(): Var Len");
    2039            description.append("Variable-length");
    2040
    2041            if (baseType != null)
    2042                description.append(" of ").append(baseType.getDescription());
    2043
    2044            break;
    2045        case CLASS_ARRAY:
    2046            log.trace("getDescription(): Array");
    2047            description.append("Array");
    2048
    2049            if (arrayDims != null) {
    2050                description.append(" [");
    2051                for (int i = 0; i < arrayDims.length; i++) {
    2052                    description.append(arrayDims[i]);
    2053                    if (i < arrayDims.length - 1)
    2054                        description.append(" x ");
    2055                }
    2056                description.append("]");
    2057            }
    2058
    2059            if (baseType != null)
    2060                description.append(" of ").append(baseType.getDescription());
    2061
    2062            break;
    2063        default:
    2064            description.append("Unknown");
    2065            break;
    2066        }
    2067        if (isNamed())
    2068            description.append("->").append(getFullName());
    2069
    2070        return description.toString();
    2071    }
    2072
    2073    /**
    2074     * Checks if a datatype specified by the identifier is an unsigned integer.
    2075     *
    2076     * @param tid
    2077     *            the datatype ID to be checked.
    2078     * @return true is the datatype is an unsigned integer; otherwise returns false.
    2079     */
    2080    public static final boolean isUnsigned(long tid) {
    2081        boolean unsigned = false;
    2082
    2083        if (tid >= 0) {
    2084            try {
    2085                int tclass = H5.H5Tget_class(tid);
    2086                log.trace("isUnsigned(): tclass = {}", tclass);
    2087                if (tclass != HDF5Constants.H5T_FLOAT
    2088                        && tclass != HDF5Constants.H5T_STRING && tclass != HDF5Constants.H5T_REFERENCE
    2089                        && tclass != HDF5Constants.H5T_BITFIELD && tclass != HDF5Constants.H5T_OPAQUE
    2090                        && tclass != HDF5Constants.H5T_VLEN && tclass != HDF5Constants.H5T_COMPOUND
    2091                        && tclass != HDF5Constants.H5T_ARRAY) {
    2092                    int tsign = H5.H5Tget_sign(tid);
    2093                    if (tsign == HDF5Constants.H5T_SGN_NONE)
    2094                        unsigned = true;
    2095                    else
    2096                        log.trace("isUnsigned(): not unsigned");
    2097                }
    2098                else {
    2099                    log.trace("isUnsigned(): tclass not integer type");
    2100                }
    2101            }
    2102            catch (Exception ex) {
    2103                log.debug("isUnsigned(): Datatype {} failure", tid, ex);
    2104                unsigned = false;
    2105            }
    2106        }
    2107        else {
    2108            log.trace("isUnsigned(): not a valid datatype");
    2109        }
    2110
    2111        return unsigned;
    2112    }
    2113
    2114    /**
    2115     * Removes all of the elements from metadata list. The list should be empty after this call returns.
    2116     */
    2117    @Override
    2118    public void clear() {
    2119        super.clear();
    2120        objMetadata.clear();
    2121    }
    2122
    2123    /**
    2124     * Retrieves the object's metadata, such as attributes, from the file. Metadata, such as attributes, is stored in a
    2125     * List.
    2126     *
    2127     * @return the list of metadata objects.
    2128     * @throws HDF5Exception
    2129     *                       if the metadata can not be retrieved
    2130     */
    2131    @Override
    2132    public List<Attribute> getMetadata()
    2133            throws HDF5Exception {
    2134        int gmIndexType = 0;
    2135        int gmIndexOrder = 0;
    2136
    2137        try {
    2138            gmIndexType = fileFormat.getIndexType(null);
    2139        }
    2140        catch (Exception ex) {
    2141            log.debug("getMetadata(): getIndexType failed: ", ex);
    2142        }
    2143        try {
    2144            gmIndexOrder = fileFormat.getIndexOrder(null);
    2145        }
    2146        catch (Exception ex) {
    2147            log.debug("getMetadata(): getIndexOrder failed: ", ex);
    2148        }
    2149        return this.getMetadata(gmIndexType, gmIndexOrder);
    2150    }
    2151
    2152    /**
    2153     * Retrieves the object's metadata, such as attributes, from the file. Metadata, such as attributes, is stored in a
    2154     * List.
    2155     *
    2156     * @param attrPropList
    2157     *                     the list of properties to get
    2158     * @return the list of metadata objects.
    2159     * @throws HDF5Exception
    2160     *                       if the metadata can not be retrieved
    2161     */
    2162    public List<Attribute> getMetadata(int... attrPropList)
    2163            throws HDF5Exception {
    2164        try {
    2165            this.linkTargetObjName = H5File.getLinkTargetName(this);
    2166        }
    2167        catch (Exception ex) {
    2168            log.debug("getMetadata(): getLinkTargetName failed: ", ex);
    2169        }
    2170
    2171        List<Attribute> attrlist = null;
    2172        try {
    2173            attrlist = objMetadata.getMetadata(attrPropList);
    2174        }
    2175        catch (Exception ex) {
    2176            log.debug("getMetadata(): getMetadata failed: ", ex);
    2177        }
    2178        return attrlist;
    2179    }
    2180
    2181    /**
    2182     * Writes a specific piece of metadata (such as an attribute) into the file. If an HDF(4&amp;5) attribute exists in
    2183     * the file, this method updates its value. If the attribute does not exist in the file, it creates the attribute in
    2184     * the file and attaches it to the object. It will fail to write a new attribute to the object where an attribute
    2185     * with the same name already exists. To update the value of an existing attribute in the file, one needs to get the
    2186     * instance of the attribute by getMetadata(), change its values, then use writeMetadata() to write the value.
    2187     *
    2188     * @param info
    2189     *             the metadata to write.
    2190     * @throws Exception
    2191     *                   if the metadata can not be written
    2192     */
    2193    @Override
    2194    public void writeMetadata(Object info)
    2195            throws Exception {
    2196        try {
    2197            objMetadata.writeMetadata(info);
    2198        }
    2199        catch (Exception ex) {
    2200            log.debug("writeMetadata(): Object not an Attribute");
    2201        }
    2202    }
    2203
    2204    /**
    2205     * Deletes an existing piece of metadata from this object.
    2206     *
    2207     * @param info
    2208     *             the metadata to delete.
    2209     * @throws HDF5Exception
    2210     *                       if the metadata can not be removed
    2211     */
    2212    @Override
    2213    public void removeMetadata(Object info)
    2214            throws HDF5Exception {
    2215        try {
    2216            objMetadata.removeMetadata(info);
    2217        }
    2218        catch (Exception ex) {
    2219            log.debug("removeMetadata(): Object not an Attribute");
    2220            return;
    2221        }
    2222
    2223        Attribute attr = (Attribute) info;
    2224        log.trace("removeMetadata(): {}", attr.getAttributeName());
    2225        long tid = open();
    2226        if (tid >= 0) {
    2227            try {
    2228                H5.H5Adelete(tid, attr.getAttributeName());
    2229            }
    2230            catch (Exception ex) {
    2231                log.debug("removeMetadata(): ", ex);
    2232            }
    2233            finally {
    2234                close(tid);
    2235            }
    2236        }
    2237        else {
    2238            log.debug("removeMetadata(): failed to open datatype");
    2239        }
    2240    }
    2241
    2242    /**
    2243     * Updates an existing piece of metadata attached to this object.
    2244     *
    2245     * @param info
    2246     *             the metadata to update.
    2247     * @throws HDF5Exception
    2248     *                       if the metadata can not be updated
    2249     */
    2250    @Override
    2251    public void updateMetadata(Object info)
    2252            throws HDF5Exception {
    2253        try {
    2254            objMetadata.updateMetadata(info);
    2255        }
    2256        catch (Exception ex) {
    2257            log.debug("updateMetadata(): Object not an Attribute");
    2258            return;
    2259        }
    2260    }
    2261
    2262    /*
    2263     * (non-Javadoc)
    2264     * @see hdf.object.HObject#setName(java.lang.String)
    2265     */
    2266    @Override
    2267    public void setName(String newName)
    2268            throws Exception {
    2269        if (newName == null)
    2270            throw new IllegalArgumentException("The new name is NULL");
    2271
    2272        H5File.renameObject(this, newName);
    2273        super.setName(newName);
    2274    }
    2275
    2276    @Override
    2277    public void setFullname(String newPath, String newName)
    2278            throws Exception {
    2279        H5File.renameObject(this, newPath, newName);
    2280        super.setFullname(newPath, newName);
    2281    }
    2282
    2283    @Override
    2284    public boolean isText() {
    2285        return (datatypeClass == Datatype.CLASS_STRING);
    2286    }
    2287
    2288    /**
    2289     * Checks if this datatype is an object reference type.
    2290     *
    2291     * @return true if the datatype is an object reference; false otherwise
    2292     */
    2293    public boolean isRefObj() {
    2294        return isRefObj;
    2295    }
    2296
    2297    /**
    2298     * Checks if this datatype is a region reference type.
    2299     *
    2300     * @return true if the datatype is a region reference; false otherwise
    2301     */
    2302    public boolean isRegRef() {
    2303        return isRegRef;
    2304    }
    2305
    2306    /**
    2307     * Checks if this datatype is a standard reference type.
    2308     *
    2309     * @return true if the datatype is a standard reference; false otherwise
    2310     */
    2311    public boolean isStdRef() {
    2312        return isStdRef;
    2313    }
    2314
    2315    /*
    2316     * (non-Javadoc)
    2317     * @see hdf.object.Datatype#getReferenceType()
    2318     */
    2319    @Override
    2320    public long getReferenceType()
    2321            throws HDF5Exception {
    2322        if (isRegRef)
    2323            return HDF5Constants.H5T_STD_REF_DSETREG;
    2324        if (isRefObj)
    2325            return HDF5Constants.H5T_STD_REF_OBJ;
    2326        if (isStdRef)
    2327            return HDF5Constants.H5T_STD_REF;
    2328        return -1;
    2329    }
    2330
    2331    /**
    2332     * Describes the dataset object description for a 1.10 reference.
    2333     *
    2334     * @param container
    2335     *                  the dataset/attribute with the reference
    2336     * @param refarr
    2337     *                  the reference datatype data to be checked.
    2338     *
    2339     * @return the dataset reference object description.
    2340     */
    2341    public static String descReferenceObject(long container, byte[] refarr) {
    2342        String region_desc = H5.H5Rget_name_string(container, HDF5Constants.H5R_OBJECT, refarr);
    2343        region_desc += " H5O_TYPE_OBJ_REF";
    2344        log.trace("descReferenceObject region_desc={}:", region_desc);
    2345        return region_desc;
    2346    }
    2347
    2348    /**
    2349     * Describes the dataset region description for a 1.10 reference.
    2350     *
    2351     * @param container
    2352     *                  the dataset/attribute with the reference
    2353     * @param refarr
    2354     *                  the reference datatype data to be checked.
    2355     *
    2356     * @return the dataset region description.
    2357     */
    2358    public static String descRegionDataset(long container, byte[] refarr) {
    2359        String region_desc = H5.H5Rget_name_string(container, HDF5Constants.H5R_DATASET_REGION, refarr);
    2360        log.trace("descRegionDataset region_desc={}:", region_desc);
    2361        long new_obj_id = HDF5Constants.H5I_INVALID_HID;
    2362        try {
    2363            log.trace("descRegionDataset refarr2={}:", refarr);
    2364            new_obj_id = H5.H5Rdereference(container, HDF5Constants.H5P_DEFAULT, HDF5Constants.H5R_DATASET_REGION,
    2365                    refarr);
    2366            long new_obj_sid = HDF5Constants.H5I_INVALID_HID;
    2367            try {
    2368                log.trace("descRegionDataset refarr3={}:", refarr);
    2369                new_obj_sid = H5.H5Rget_region(container, HDF5Constants.H5R_DATASET_REGION, refarr);
    2370                try {
    2371                    int region_type = H5.H5Sget_select_type(new_obj_sid);
    2372                    log.debug("descRegionDataset Reference Region Type {}", region_type);
    2373                    long reg_ndims = H5.H5Sget_simple_extent_ndims(new_obj_sid);
    2374                    StringBuilder sb = new StringBuilder();
    2375                    if (HDF5Constants.H5S_SEL_POINTS == region_type) {
    2376                        sb.append(" REGION_TYPE POINT ");
    2377                        long reg_npoints = H5.H5Sget_select_elem_npoints(new_obj_sid);
    2378                        long getcoord[] = new long[(int) (reg_ndims * reg_npoints)];
    2379                        try {
    2380                            H5.H5Sget_select_elem_pointlist(new_obj_sid, 0, reg_npoints, getcoord);
    2381                        }
    2382                        catch (Exception ex5) {
    2383                            log.debug("descRegionDataset H5.H5Sget_select_elem_pointlist: ", ex5);
    2384                        }
    2385                        sb.append("{ ");
    2386                        for (int i = 0; i < (int) reg_npoints; i++) {
    2387                            if (i > 0)
    2388                                sb.append(" ");
    2389                            sb.append("(");
    2390                            for (int j = 0; j < (int) reg_ndims; j++) {
    2391                                if (j > 0)
    2392                                    sb.append(",");
    2393                                sb.append(getcoord[i * (int) reg_ndims + j]);
    2394                            }
    2395                            sb.append(")");
    2396                        }
    2397                        sb.append(" }");
    2398                        region_desc += sb.toString();
    2399                    }
    2400                    else if (HDF5Constants.H5S_SEL_HYPERSLABS == region_type) {
    2401                        sb.append(" REGION_TYPE BLOCK ");
    2402                        long reg_nblocks = H5.H5Sget_select_hyper_nblocks(new_obj_sid);
    2403                        long getblocks[] = new long[(int) (reg_ndims * reg_nblocks) * 2];
    2404                        try {
    2405                            H5.H5Sget_select_hyper_blocklist(new_obj_sid, 0, reg_nblocks, getblocks);
    2406                        }
    2407                        catch (Exception ex5) {
    2408                            log.debug("descRegionDataset H5.H5Sget_select_hyper_blocklist: ", ex5);
    2409                        }
    2410                        sb.append("{ ");
    2411                        for (int i = 0; i < (int) reg_nblocks; i++) {
    2412                            if (i > 0)
    2413                                sb.append(" ");
    2414                            sb.append("(");
    2415                            for (int j = 0; j < (int) reg_ndims; j++) {
    2416                                if (j > 0)
    2417                                    sb.append(",");
    2418                                sb.append(getblocks[i * 2 * (int) reg_ndims + j]);
    2419                            }
    2420                            sb.append(")-(");
    2421                            for (int j = 0; j < (int) reg_ndims; j++) {
    2422                                if (j > 0)
    2423                                    sb.append(",");
    2424                                sb.append(getblocks[i * 2 * (int) reg_ndims + (int) reg_ndims + j]);
    2425                            }
    2426                            sb.append(")");
    2427                        }
    2428                        sb.append(" }");
    2429                        region_desc += sb.toString();
    2430                    }
    2431                    else
    2432                        region_desc += " REGION_TYPE UNKNOWN";
    2433                }
    2434                catch (Exception ex4) {
    2435                    log.debug("descRegionDataset Region Type", ex4);
    2436                }
    2437            }
    2438            catch (Exception ex3) {
    2439                log.debug("descRegionDataset Space Open", ex3);
    2440            }
    2441            finally {
    2442                H5.H5Sclose(new_obj_sid);
    2443            }
    2444            log.trace("descRegionDataset finish");
    2445        }
    2446        catch (Exception ex2) {
    2447            log.debug("descRegionDataset ", ex2);
    2448        }
    2449        finally {
    2450            H5.H5Dclose(new_obj_id);
    2451        }
    2452        return region_desc;
    2453    }
    2454
    2455    /**
    2456     * Gets the dataset reference type for a 1.10 reference.
    2457     *
    2458     * @param container
    2459     *                  the dataset/attribute with the reference
    2460     * @param refarr
    2461     *                  the reference datatype data to be checked.
    2462     *
    2463     * @return the dataset reference type.
    2464     */
    2465    public static int typeObjectRef(long container, int obj_type, byte[] refarr) {
    2466        int ref_type = -1;
    2467        long new_obj_id = HDF5Constants.H5I_INVALID_HID;
    2468        try {
    2469            log.trace("typeObjectRef refarr2={}:", refarr);
    2470            new_obj_id = H5.H5Rdereference(container, HDF5Constants.H5P_DEFAULT, obj_type, refarr);
    2471            if (HDF5Constants.H5R_DATASET_REGION == obj_type) {
    2472                long new_obj_sid = HDF5Constants.H5I_INVALID_HID;
    2473                try {
    2474                    log.trace("typeObjectRef refarr3={}:", refarr);
    2475                    new_obj_sid = H5.H5Rget_region(container, HDF5Constants.H5R_DATASET_REGION, refarr);
    2476                    try {
    2477                        ref_type = H5.H5Sget_select_type(new_obj_sid);
    2478                        log.debug("typeObjectRef Reference Region Type {}", ref_type);
    2479                    }
    2480                    catch (Exception ex4) {
    2481                        log.debug("typeObjectRef Region Type", ex4);
    2482                    }
    2483                }
    2484                catch (Exception ex3) {
    2485                    log.debug("typeObjectRef Space Open", ex3);
    2486                }
    2487                finally {
    2488                    H5.H5Sclose(new_obj_sid);
    2489                }
    2490            }
    2491            else {
    2492                H5O_info_t objInfo;
    2493
    2494                objInfo = H5.H5Oget_info(new_obj_id);
    2495                ref_type = objInfo.type;
    2496            }
    2497            log.trace("typeObjectRef finish");
    2498        }
    2499        catch (Exception ex2) {
    2500            log.debug("typeObjectRef ", ex2);
    2501        }
    2502        finally {
    2503            H5.H5Dclose(new_obj_id);
    2504        }
    2505        return ref_type;
    2506    }
    2507
    2508    /**
    2509     * Checks if a reference datatype is all zero.
    2510     *
    2511     * @param refarr
    2512     *               the reference datatype data to be checked.
    2513     * @return true is the reference datatype data is all zero; otherwise returns false.
    2514     */
    2515    public static boolean zeroArrayCheck(final byte[] refarr) {
    2516        for (byte b : refarr) {
    2517            if (b != 0)
    2518                return false;
    2519        }
    2520        return true;
    2521    }
    2522
    2523    /**
    2524     * Gets the string padding.
    2525     *
    2526     * @return the string padding value
    2527     */
    2528    public int getNativeStrPad() {
    2529        return nativeStrPad;
    2530    }
    2531
    2532    /**
    2533     * Extracts compound information into flat structure. For example, compound datatype "nest" has {nest1{a, b, c}, d,
    2534     * e} then extractCompoundInfo() will put the names of nested compound fields into a flat list as
    2535     *
    2536     * <pre>
    2537     * nest.nest1.a
    2538     * nest.nest1.b
    2539     * nest.nest1.c
    2540     * nest.d
    2541     * nest.e
    2542     * </pre>
    2543     *
    2544     * @param dtype
    2545     *                      the datatype to extract compound info from
    2546     * @param name
    2547     *                      the name of the compound datatype
    2548     * @param names
    2549     *                      the list to store the member names of the compound datatype
    2550     * @param flatListTypes
    2551     *                      the list to store the nested member names of the compound datatype
    2552     */
    2553    public static void extractCompoundInfo(final H5Datatype dtype, String name, List<String> names,
    2554            List<Datatype> flatListTypes) {
    2555        log.trace("extractCompoundInfo(): start: name={}", name);
    2556
    2557        if (dtype.isArray()) {
    2558            log.trace("extractCompoundInfo(): array type - extracting compound info from base datatype");
    2559            H5Datatype.extractCompoundInfo((H5Datatype) dtype.getDatatypeBase(), name, names, flatListTypes);
    2560        }
    2561        else if (dtype.isVLEN()
    2562                && !dtype.isVarStr()) {
    2563            log.trace("extractCompoundInfo(): variable-length type - extracting compound info from base datatype");
    2564            H5Datatype.extractCompoundInfo((H5Datatype) dtype.getDatatypeBase(), name, names, flatListTypes);
    2565        }
    2566        else if (dtype.isCompound()) {
    2567            List<String> compoundMemberNames = dtype.getCompoundMemberNames();
    2568            List<Datatype> compoundMemberTypes = dtype.getCompoundMemberTypes();
    2569            Datatype mtype = null;
    2570            String mname = null;
    2571
    2572            if (compoundMemberNames == null) {
    2573                log.debug("extractCompoundInfo(): compoundMemberNames is null");
    2574                return;
    2575            }
    2576
    2577            if (compoundMemberNames.isEmpty()) {
    2578                log.debug("extractCompoundInfo(): compound datatype has no members");
    2579                return;
    2580            }
    2581
    2582            log.trace("extractCompoundInfo(): nMembers={}", compoundMemberNames.size());
    2583
    2584            for (int i = 0; i < compoundMemberNames.size(); i++) {
    2585                log.trace("extractCompoundInfo(): member[{}]:", i);
    2586
    2587                mtype = compoundMemberTypes.get(i);
    2588
    2589                log.trace("extractCompoundInfo(): type={} with size={}", mtype.getDescription(),
    2590                        mtype.getDatatypeSize());
    2591
    2592                if (names != null) {
    2593                    mname = name + compoundMemberNames.get(i);
    2594                    log.trace("extractCompoundInfo(): mname={}, name={}", mname, name);
    2595                }
    2596
    2597                if (mtype.isCompound()) {
    2598                    H5Datatype.extractCompoundInfo((H5Datatype) mtype, mname + CompoundDS.SEPARATOR, names,
    2599                            flatListTypes);
    2600                    log.trace("extractCompoundInfo(): continue after recursive compound");
    2601                    continue;
    2602                }
    2603
    2604                if (names != null) {
    2605                    names.add(mname);
    2606                }
    2607
    2608                flatListTypes.add(mtype);
    2609
    2610                /*
    2611                 * For ARRAY of COMPOUND and VLEN of COMPOUND types, we first add the top-level array or vlen type to
    2612                 * the list of datatypes, and then follow that with a listing of the datatypes inside the nested
    2613                 * compound.
    2614                 */
    2615                /*
    2616                 * TODO: Don't flatten variable-length types until true variable-length support is implemented.
    2617                 */
    2618                if (mtype.isArray() /* || (mtype.isVLEN() && !mtype.isVarStr()) */) {
    2619                    H5Datatype.extractCompoundInfo((H5Datatype) mtype, mname + CompoundDS.SEPARATOR, names,
    2620                            flatListTypes);
    2621                }
    2622            }
    2623        }
    2624    }
    2625
    2626    /**
    2627     * Creates a datatype of a compound with one field. This function is needed to read/write data field by field.
    2628     *
    2629     * @param memberName
    2630     *                   The name of the datatype
    2631     * @return the identifier of the compound datatype.
    2632     * @throws HDF5Exception
    2633     *                       If there is an error at the HDF5 library level.
    2634     */
    2635    public long createCompoundFieldType(String memberName)
    2636            throws HDF5Exception {
    2637        log.trace("createCompoundFieldType(): start member_name={}", memberName);
    2638
    2639        long topTID = HDF5Constants.H5I_INVALID_HID;
    2640        long tmpTID1 = HDF5Constants.H5I_INVALID_HID;
    2641
    2642        try {
    2643            if (this.isArray()) {
    2644                log.trace("createCompoundFieldType(): array datatype");
    2645
    2646                if (baseType != null) {
    2647                    log.trace("createCompoundFieldType(): creating compound field type from base datatype");
    2648                    tmpTID1 = ((H5Datatype) baseType).createCompoundFieldType(memberName);
    2649                }
    2650
    2651                log.trace("createCompoundFieldType(): creating container array datatype");
    2652                topTID = H5.H5Tarray_create(tmpTID1, arrayDims.length, arrayDims);
    2653            }
    2654            else if (this.isVLEN()) {
    2655                log.trace("createCompoundFieldType(): variable-length datatype");
    2656
    2657                if (baseType != null) {
    2658                    log.trace("createCompoundFieldType(): creating compound field type from base datatype");
    2659                    tmpTID1 = ((H5Datatype) baseType).createCompoundFieldType(memberName);
    2660                }
    2661
    2662                log.trace("createCompoundFieldType(): creating container variable-length datatype");
    2663                topTID = H5.H5Tvlen_create(tmpTID1);
    2664            }
    2665            else if (this.isCompound()) {
    2666                log.trace("createCompoundFieldType(): compound datatype");
    2667
    2668                String insertedName = memberName;
    2669
    2670                int sep = memberName.indexOf(CompoundDS.SEPARATOR);
    2671                if (sep >= 0) {
    2672                    /*
    2673                     * If a compound separator character is present in the supplied string, then there is an additional
    2674                     * level of compound nesting. We will create a compound type to hold the nested compound type.
    2675                     */
    2676                    insertedName = memberName.substring(0, sep);
    2677
    2678                    log.trace("createCompoundFieldType(): member with name {} is nested inside compound", insertedName);
    2679                }
    2680
    2681                /*
    2682                 * Retrieve the index of the compound member by its name.
    2683                 */
    2684                int memberIndex = this.compoundMemberNames.indexOf(insertedName);
    2685                if (memberIndex >= 0) {
    2686                    H5Datatype memberType = (H5Datatype) this.compoundMemberTypes.get(memberIndex);
    2687
    2688                    log.trace("createCompoundFieldType(): Member {} is type {} of size={} with baseType={}",
    2689                            insertedName, memberType.getDescription(), memberType.getDatatypeSize(),
    2690                            memberType.getDatatypeBase());
    2691
    2692                    if (sep >= 0)
    2693                        /*
    2694                         * Additional compound nesting; create the nested compound type.
    2695                         */
    2696                        tmpTID1 = memberType.createCompoundFieldType(memberName.substring(sep + 1));
    2697                    else
    2698                        tmpTID1 = memberType.createNative();
    2699
    2700                    log.trace("createCompoundFieldType(): creating container compound datatype");
    2701                    topTID = H5.H5Tcreate(HDF5Constants.H5T_COMPOUND, datatypeSize);
    2702
    2703                    log.trace("createCompoundFieldType(): inserting member {} into compound datatype", insertedName);
    2704                    H5.H5Tinsert(topTID, insertedName, 0, tmpTID1);
    2705
    2706                    /*
    2707                     * WARNING!!! This step is crucial. Without it, the compound type created might be larger than the
    2708                     * size of the single datatype field we are inserting. Performing a read with a compound datatype of
    2709                     * an incorrect size will corrupt JVM memory and cause strange behavior and crashes.
    2710                     */
    2711                    H5.H5Tpack(topTID);
    2712                }
    2713                else {
    2714                    log.debug(
    2715                            "createCompoundFieldType(): member name {} not found in compound datatype's member name list",
    2716                            memberName);
    2717                }
    2718            }
    2719        }
    2720        catch (Exception ex) {
    2721            log.debug("createCompoundFieldType(): creation of compound field type failed: ", ex);
    2722            topTID = HDF5Constants.H5I_INVALID_HID;
    2723        }
    2724        finally {
    2725            close(tmpTID1);
    2726        }
    2727
    2728        return topTID;
    2729    }
    2730
    2731    private boolean datatypeIsComplex(long tid) {
    2732        long tclass = HDF5Constants.H5T_NO_CLASS;
    2733
    2734        try {
    2735            tclass = H5.H5Tget_class(tid);
    2736            log.trace("datatypeIsComplex():{}", tclass);
    2737        }
    2738        catch (Exception ex) {
    2739            log.debug("datatypeIsComplex():", ex);
    2740        }
    2741
    2742        boolean retVal = (tclass == HDF5Constants.H5T_COMPOUND);
    2743        retVal |= (tclass == HDF5Constants.H5T_ENUM);
    2744        retVal |= (tclass == HDF5Constants.H5T_VLEN);
    2745        retVal |= (tclass == HDF5Constants.H5T_ARRAY);
    2746
    2747        return retVal;
    2748    }
    2749
    2750    private boolean datatypeIsReference(long tid) {
    2751        long tclass = HDF5Constants.H5T_NO_CLASS;
    2752
    2753        try {
    2754            tclass = H5.H5Tget_class(tid);
    2755            log.trace("datatypeIsReference():{}", tclass);
    2756        }
    2757        catch (Exception ex) {
    2758            log.debug("datatypeIsReference():", ex);
    2759        }
    2760
    2761        return (tclass == HDF5Constants.H5T_REFERENCE);
    2762    }
    2763
    2764    private boolean datatypeIsAtomic(long tid) {
    2765        boolean retVal = !(datatypeIsComplex(tid)
    2766                | datatypeIsReference(tid) | isRef());
    2767        retVal |= isOpaque();
    2768        retVal |= isBitField();
    2769
    2770        return retVal;
    2771    }
    2772
    2773    private boolean datatypeClassIsComplex(long tclass) {
    2774        boolean retVal = (tclass == HDF5Constants.H5T_COMPOUND);
    2775        retVal |= (tclass == HDF5Constants.H5T_ENUM);
    2776        retVal |= (tclass == HDF5Constants.H5T_VLEN);
    2777        retVal |= (tclass == HDF5Constants.H5T_ARRAY);
    2778
    2779        return retVal;
    2780    }
    2781
    2782    private boolean datatypeClassIsReference(long tclass) {
    2783        return (tclass == HDF5Constants.H5T_REFERENCE);
    2784    }
    2785
    2786    private boolean datatypeClassIsOpaque(long tclass) {
    2787        return (tclass == Datatype.CLASS_OPAQUE);
    2788    }
    2789
    2790    private boolean datatypeClassIsAtomic(long tclass) {
    2791        boolean retVal = !(datatypeClassIsComplex(tclass)
    2792                | datatypeClassIsReference(tclass));
    2793        retVal |= (tclass == Datatype.CLASS_OPAQUE);
    2794        retVal |= (tclass == Datatype.CLASS_BITFIELD);
    2795
    2796        return retVal;
    2797    }
    2798}