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