    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.util.HashMap;
    019import java.util.Iterator;
    020import java.util.List;
    021import java.util.Map.Entry;
    022import java.util.Objects;
    023import java.util.Vector;
    024
    025import hdf.hdf5lib.H5;
    026import hdf.hdf5lib.HDF5Constants;
    027import hdf.hdf5lib.HDFNativeData;
    028import hdf.hdf5lib.exceptions.HDF5Exception;
    029import hdf.hdf5lib.exceptions.HDF5LibraryException;
    030import hdf.hdf5lib.structs.H5O_info_t;
    031import hdf.object.Attribute;
    032import hdf.object.CompoundDS;
    033import hdf.object.Datatype;
    034import hdf.object.FileFormat;
    035
    036/**
    037 * This class defines HDF5 datatype characteristics and APIs for a data type.
    038 * <p>
    039 * This class provides several methods to convert an HDF5 datatype identifier to a datatype object, and vice versa. A
    040 * datatype object is described by four basic fields: datatype class, size, byte order, and sign, while an HDF5 datatype
    041 * is presented by a datatype identifier.
    042 *
    043 * @version 1.1 9/4/2007
    044 * @author Peter X. Cao
    045 */
    046public class H5Datatype extends Datatype {
    047    private static final long serialVersionUID = -750546422258749792L;
    048
    049    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(H5Datatype.class);
    050
    051    /**
    052     * The list of attributes of this data object.
    053     */
    054    private List<Attribute> attributeList;
    055
    056    /** Flag to indicate if this datatype is a named datatype */
    057    private boolean isNamed = false;
    058
    059    private boolean is_ref_obj = false;
    060
    061    private boolean is_reg_ref = false;
    062
    063    private int nAttributes = -1;
    064
    065    private H5O_info_t obj_info;
    066
    067    /**
    068     * The native class of the datatype.
    069     */
    070    private int nativeClass = -1;
    071
    072    private int nativeStrPad = -1;
    073
    074    /**
    075     * The tag for an opaque datatype.
    076     */
    077    private String opaqueTag = null;
    078
    079    /**
    080     * Constructs an named HDF5 data type object for a given file, dataset name and group path.
    081     * <p>
    082     * The datatype object represents an existing named datatype in file. For example,
    083     *
    084     * <pre>
    085     * new H5Datatype(file, "dtype1", "/g0")
    086     * </pre>
    087     *
    088     * constructs a datatype object that corresponds to the dataset,"dset1", at group "/g0".
    089     *
    090     * @param theFile
    091     *            the file that contains the dataset.
    092     * @param name
    093     *            the name of the dataset such as "dset1".
    094     * @param path
    095     *            the group path to the dataset such as "/g0/".
    096     */
    097    public H5Datatype(FileFormat theFile, String name, String path) {
    098        this(theFile, name, path, null);
    099    }
    100
    101    /**
    102     * @deprecated Not for public use in the future. <br>
    103     *             Using {@link #H5Datatype(FileFormat, String, String)}
    104     *
    105     * @param theFile
    106     *            the file that contains the dataset.
    107     * @param name
    108     *            the name of the dataset such as "dset1".
    109     * @param path
    110     *            the group path to the dataset such as "/g0/".
    111     * @param oid
    112     *            the oid of the dataset.
    113     */
    114    @Deprecated
    115    public H5Datatype(FileFormat theFile, String name, String path, long[] oid) {
    116        super(theFile, name, path, oid);
    117        obj_info = new H5O_info_t(-1L, -1L, 0, 0, -1L, 0L, 0L, 0L, 0L, null, null, null);
    118
    119        if ((oid == null) && (theFile != null)) {
    120            // retrieve the object ID
    121            try {
    122                byte[] ref_buf = H5.H5Rcreate(theFile.getFID(), this.getFullName(), HDF5Constants.H5R_OBJECT, -1);
    123                this.oid = new long[1];
    124                this.oid[0] = HDFNativeData.byteToLong(ref_buf, 0);
    125            }
    126            catch (Exception ex) {
    127                log.debug("constructor ID {} for {} failed H5Rcreate", theFile.getFID(), this.getFullName());
    128            }
    129        }
    130
    131        long tid = -1;
    132        try {
    133            tid = H5.H5Topen(theFile.getFID(), this.getFullName(), HDF5Constants.H5P_DEFAULT);
    134            fromNative(tid);
    135        }
    136        catch (Exception ex) {
    137            log.debug("constructor H5Topen() failure");
    138        }
    139        finally {
    140            close(tid);
    141        }
    142    }
    143
    144    /**
    145     * Constructs a Datatype with specified class, size, byte order and sign.
    146     * <p>
    147     * The following is a list of a few example of H5Datatype.
    148     * <ol>
    149     * <li>to create unsigned native integer<br>
    150     * H5Datatype type = new H5Dataype(CLASS_INTEGER, NATIVE, NATIVE, SIGN_NONE);
    151     * <li>to create 16-bit signed integer with big endian<br>
    152     * H5Datatype type = new H5Dataype(CLASS_INTEGER, 2, ORDER_BE, NATIVE);
    153     * <li>to create native float<br>
    154     * H5Datatype type = new H5Dataype(CLASS_FLOAT, NATIVE, NATIVE, -1);
    155     * <li>to create 64-bit double<br>
    156     * H5Datatype type = new H5Dataype(CLASS_FLOAT, 8, NATIVE, -1);
    157     * </ol>
    158     *
    159     * @param tclass
    160     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    161     * @param tsize
    162     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
    163     * @param torder
    164     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX and ORDER_NONE
    165     * @param tsign
    166     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and MSGN
    167     */
    168    public H5Datatype(int tclass, int tsize, int torder, int tsign) {
    169        this(tclass, tsize, torder, tsign, null);
    170    }
    171
    172    /**
    173     * Constructs a Datatype with specified class, size, byte order and sign.
    174     * <p>
    175     * The following is a list of a few example of H5Datatype.
    176     * <ol>
    177     * <li>to create unsigned native integer<br>
    178     * H5Datatype type = new H5Dataype(CLASS_INTEGER, NATIVE, NATIVE, SIGN_NONE);
    179     * <li>to create 16-bit signed integer with big endian<br>
    180     * H5Datatype type = new H5Dataype(CLASS_INTEGER, 2, ORDER_BE, NATIVE);
    181     * <li>to create native float<br>
    182     * H5Datatype type = new H5Dataype(CLASS_FLOAT, NATIVE, NATIVE, -1);
    183     * <li>to create 64-bit double<br>
    184     * H5Datatype type = new H5Dataype(CLASS_FLOAT, 8, NATIVE, -1);
    185     * </ol>
    186     *
    187     * @param tclass
    188     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    189     * @param tsize
    190     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
    191     * @param torder
    192     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX and ORDER_NONE
    193     * @param tsign
    194     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and MSGN
    195     * @param tbase
    196     *            the base datatype of the new datatype
    197     */
    198    public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) {
    199        this(tclass, tsize, torder, tsign, tbase, null);
    200    }
    201
    202    /**
    203     * Constructs a Datatype with specified class, size, byte order and sign.
    204     * <p>
    205     * The following is a list of a few example of H5Datatype.
    206     * <ol>
    207     * <li>to create unsigned native integer<br>
    208     * H5Datatype type = new H5Dataype(CLASS_INTEGER, NATIVE, NATIVE, SIGN_NONE);
    209     * <li>to create 16-bit signed integer with big endian<br>
    210     * H5Datatype type = new H5Dataype(CLASS_INTEGER, 2, ORDER_BE, NATIVE);
    211     * <li>to create native float<br>
    212     * H5Datatype type = new H5Dataype(CLASS_FLOAT, NATIVE, NATIVE, -1);
    213     * <li>to create 64-bit double<br>
    214     * H5Datatype type = new H5Dataype(CLASS_FLOAT, 8, NATIVE, -1);
    215     * </ol>
    216     *
    217     * @param tclass
    218     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    219     * @param tsize
    220     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
    221     * @param torder
    222     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX and
    223     *            ORDER_NONE
    224     * @param tsign
    225     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and MSGN
    226     * @param tbase
    227     *            the base datatype of the new datatype
    228     * @param pbase
    229     *            the parent datatype of the new datatype
    230     */
    231    public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase) {
    232        this(tclass, tsize, torder, tsign, tbase, pbase, null);
    233    }
    234
    235    /**
    236     * Constructs a Datatype with specified class, size, byte order and sign.
    237     * <p>
    238     * The following is a list of a few example of H5Datatype.
    239     * <ol>
    240     * <li>to create unsigned native integer<br>
    241     * H5Datatype type = new H5Dataype(CLASS_INTEGER, NATIVE, NATIVE, SIGN_NONE);
    242     * <li>to create 16-bit signed integer with big endian<br>
    243     * H5Datatype type = new H5Dataype(CLASS_INTEGER, 2, ORDER_BE, NATIVE);
    244     * <li>to create native float<br>
    245     * H5Datatype type = new H5Dataype(CLASS_FLOAT, NATIVE, NATIVE, -1);
    246     * <li>to create 64-bit double<br>
    247     * H5Datatype type = new H5Dataype(CLASS_FLOAT, 8, NATIVE, -1);
    248     * </ol>
    249     *
    250     * @param tclass
    251     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    252     * @param tsize
    253     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
    254     * @param torder
    255     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX and
    256     *            ORDER_NONE
    257     * @param tsign
    258     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and MSGN
    259     * @param tbase
    260     *            the base datatype of the new datatype
    261     * @param pbase
    262     *            the parent datatype of the new datatype
    263     * @param members
    264     *            the list of member datatypes
    265     */
    266    public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase, List<H5Datatype> members) {
    267        super(tclass, tsize, torder, tsign, tbase, pbase);
    268        if (members == null) {
    269            compoundMemberTypes = new Vector<>();
    270        }
    271        else {
    272            compoundMemberTypes = new Vector<>(members.size());
    273            compoundMemberTypes.addAll(members);
    274        }
    275
    276        datatypeDescription = getDescription();
    277    }
    278
    279    /**
    280     * Constructs a Datatype with a given native datatype identifier.
    281     * <p>
    282     * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5,
    283     *
    284     * <pre>
    285     * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
    286     * Datatype dtype = new Datatype(tid);
    287     * </pre>
    288     *
    289     * will construct a datatype equivalent to new Datatype(CLASS_INTEGER, 4, NATIVE, SIGN_NONE);
    290     *
    291     * @see #fromNative(long nativeID)
    292     *
    293     * @param nativeID
    294     *            the native datatype identifier.
    295     */
    296    public H5Datatype(long nativeID) {
    297        this(nativeID, null);
    298    }
    299
    300    /**
    301     * Constructs a Datatype with a given native datatype identifier.
    302     * <p>
    303     * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5,
    304     *
    305     * <pre>
    306     * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
    307     * Datatype dtype = new Datatype(tid);
    308     * </pre>
    309     *
    310     * will construct a datatype equivalent to new Datatype(CLASS_INTEGER, 4, NATIVE, SIGN_NONE);
    311     *
    312     * @see #fromNative(long nativeID)
    313     *
    314     * @param nativeID
    315     *            the native datatype identifier.
    316     * @param pbase
    317     *            the parent datatype of the new datatype
    318     */
    319    public H5Datatype(long nativeID, Datatype pbase) {
    320        super(nativeID, pbase);
    321        fromNative(nativeID);
    322        datatypeDescription = getDescription();
    323    }
    324
    325    /**
    326     * Opens access to a named datatype.
    327     * <p>
    328     * It calls H5.H5Topen(loc, name).
    329     *
    330     * @return the datatype identifier if successful; otherwise returns negative value.
    331     *
    332     * @see hdf.hdf5lib.H5#H5Topen(long, String, long)
    333     */
    334    @Override
    335    public long open() {
    336        log.trace("open(): start");
    337        long tid = -1;
    338
    339        try {
    340            tid = H5.H5Topen(getFID(), getPath() + getName(), HDF5Constants.H5P_DEFAULT);
    341        }
    342        catch (HDF5Exception ex) {
    343            tid = -1;
    344        }
    345
    346        log.trace("open(): finish");
    347        return tid;
    348    }
    349
    350    /**
    351     * Closes a datatype identifier.
    352     * <p>
    353     * It calls H5.H5close(tid).
    354     *
    355     * @param tid
    356     *            the datatype ID to close
    357     */
    358    @Override
    359    public void close(long tid) {
    360        if (tid >= 0) {
    361            try {
    362                H5.H5Tclose(tid);
    363            }
    364            catch (HDF5Exception ex) {
    365                log.debug("close(): H5Tclose(tid {}) failure: ", tid, ex);
    366            }
    367        }
    368    }
    369
    370    /*
    371     * (non-Javadoc)
    372     *
    373     * @see hdf.object.DataFormat#hasAttribute()
    374     */
    375    @Override
    376    public boolean hasAttribute() {
    377        obj_info.num_attrs = nAttributes;
    378
    379        if (obj_info.num_attrs < 0) {
    380            long tid = -1;
    381            try {
    382                tid = H5.H5Topen(getFID(), getPath() + getName(), HDF5Constants.H5P_DEFAULT);
    383                fromNative(tid);
    384                obj_info = H5.H5Oget_info(tid);
    385                isNamed = true;
    386            }
    387            catch (Exception ex) {
    388                obj_info.num_attrs = 0;
    389            }
    390            finally {
    391                close(tid);
    392            }
    393        }
    394
    395        log.trace("hasAttribute(): nAttributes={}", obj_info.num_attrs);
    396
    397        return (obj_info.num_attrs > 0);
    398    }
    399
    400    /**
    401     * Converts values in an Enumeration Datatype to names.
    402     * <p>
    403     * This method searches the identified enumeration datatype for the values appearing in
    404     * <code>inValues</code> and returns the names corresponding to those values. If a given value is
    405     * not found in the enumeration datatype, the name corresponding to that value will be set to
    406     * <code>"ENUM ERR value"</code> in the string array that is returned.
    407     * <p>
    408     * If the method fails in general, null will be returned instead of a String array. An empty
    409     * <code>inValues</code> parameter would cause general failure.
    410     *
    411     * @param inValues
    412     *            The array of enumerations values to be converted.
    413     *
    414     * @return The string array of names if successful; otherwise return null.
    415     *
    416     * @throws HDF5Exception
    417     *             If there is an error at the HDF5 library level.
    418     *
    419     */
    420    public String[] convertEnumValueToName(Object inValues) throws HDF5Exception {
    421        log.trace("convertEnumValueToName() inValues={} start", inValues);
    422        int inSize = 0;
    423        String[] outNames = null;
    424        String cName = inValues.getClass().getName();
    425        boolean isArray = cName.lastIndexOf("[") >= 0;
    426        if (isArray) {
    427            inSize = Array.getLength(inValues);
    428        }
    429        else {
    430            inSize = 1;
    431        }
    432
    433        if ((inValues == null) || (inSize <= 0)) {
    434            log.debug("convertEnumValueToName() failure: in values null or inSize length invalid");
    435            log.debug("convertEnumValueToName(): inValues={} inSize={}", inValues, inSize);
    436            log.trace("convertEnumValueToName(): finish");
    437            return null;
    438        }
    439
    440        if (enumMembers == null || enumMembers.size() <= 0) {
    441            log.debug("convertEnumValueToName(): no members");
    442            log.trace("convertEnumValueToName(): finish");
    443            return null;
    444        }
    445
    446        log.trace("convertEnumValueToName(): inSize={} nMembers={} enums={}", inSize, enumMembers.size(), enumMembers);
    447        outNames = new String[inSize];
    448        for (int i = 0; i < inSize; i++) {
    449            if (isArray) {
    450                if (enumMembers.containsKey(String.valueOf(Array.get(inValues, i)))) {
    451                    outNames[i] = enumMembers.get(String.valueOf(Array.get(inValues, i)));
    452                }
    453                else {
    454                    outNames[i] = "**ENUM ERR " + String.valueOf(Array.get(inValues, i)) + "**";
    455                }
    456            }
    457            else {
    458                if (enumMembers.containsKey(String.valueOf(inValues))) {
    459                    outNames[i] = enumMembers.get(String.valueOf(inValues));
    460                }
    461                else {
    462                    outNames[i] = "**ENUM ERR " + String.valueOf(inValues) + "**";
    463                }
    464            }
    465        }
    466
    467        log.trace("convertEnumValueToName(): finish");
    468        return outNames;
    469    }
    470
    471    /**
    472     * Converts names in an Enumeration Datatype to values.
    473     * <p>
    474     * This method searches the identified enumeration datatype for the names appearing in
    475     * <code>inValues</code> and returns the values corresponding to those names.
    476     *
    477     * @param in
    478     *            The array of enumerations names to be converted.
    479     *
    480     * @return The int array of values if successful; otherwise return null.
    481     *
    482     * @throws HDF5Exception
    483     *             If there is an error at the HDF5 library level.
    484     *
    485     */
    486    public Object[] convertEnumNameToValue(String[] in) throws HDF5Exception {
    487        log.trace("convertEnumNameToValue() start");
    488        int size = 0;
    489
    490        if ((in == null) || ((size = Array.getLength(in)) <= 0)) {
    491            log.debug("convertEnumNameToValue() failure: in values null or in size not valid");
    492            log.debug("convertEnumNameToValue(): in={} inSize={}", in.toString(), in.length);
    493            log.trace("convertEnumNameToValue(): finish");
    494            return null;
    495        }
    496
    497        if (enumMembers == null || enumMembers.size() <= 0) {
    498            log.debug("convertEnumNameToValue(): no members");
    499            log.trace("convertEnumNameToValue(): finish");
    500            return null;
    501        }
    502
    503        Object[] out = null;
    504        if (datatypeSize == 1) {
    505            out = new Byte[size];
    506        }
    507        else if (datatypeSize == 2) {
    508            out = new Short[size];
    509        }
    510        else if (datatypeSize == 4) {
    511            out = new Integer[size];
    512        }
    513        else if (datatypeSize == 8) {
    514            out = new Long[size];
    515        }
    516        else {
    517            out = new Object[size];
    518        }
    519
    520        for (int i = 0; i < size; i++) {
    521            if (in[i] == null || in[i].length() <= 0)
    522                continue;
    523
    524            for (Entry<String, String> entry : enumMembers.entrySet()) {
    525                if (Objects.equals(in[i], entry.getValue())) {
    526                    if (datatypeSize == 1) {
    527                        log.trace("convertEnumNameToValue(): ENUM is H5T_NATIVE_INT8");
    528                        out[i] = Byte.parseByte(entry.getKey());
    529                    }
    530                    else if (datatypeSize == 2) {
    531                        log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT16");
    532                        out[i] = Short.parseShort(entry.getKey());
    533                    }
    534                    else if (datatypeSize == 4) {
    535                        log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT32");
    536                        out[i] = Integer.parseInt(entry.getKey());
    537                    }
    538                    else if (datatypeSize == 8) {
    539                        log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT64");
    540                        out[i] = Long.parseLong(entry.getKey());
    541                    }
    542                    else {
    543                        log.debug("convertEnumNameToValue(): enum datatypeSize incorrect");
    544                        out[i] = -1;
    545                    }
    546                    break;
    547                }
    548            }
    549        }
    550
    551        log.trace("convertEnumNameToValue(): finish");
    552        return out;
    553    }
    554
    555    /*
    556     * (non-Javadoc)
    557     *
    558     * @see hdf.object.Datatype#fromNative(int)
    559     */
    560    @Override
    561    public void fromNative(long tid) {
    562        log.trace("fromNative(): start: tid={}", tid);
    563        long tsize = -1;
    564        int torder = -1;
    565        boolean isChar = false, isUchar = false;
    566
    567        if (tid < 0) {
    568            datatypeClass = CLASS_NO_CLASS;
    569        }
    570        else {
    571            try {
    572                nativeClass = H5.H5Tget_class(tid);
    573                tsize = H5.H5Tget_size(tid);
    574                torder = H5.H5Tget_order(tid);
    575                is_variable_str = H5.H5Tis_variable_str(tid);
    576                is_VLEN = false;
    577                log.trace("fromNative(): tclass={}, tsize={}, torder={}, isVLEN={}", nativeClass, tsize, torder, is_VLEN);
    578            }
    579            catch (Exception ex) {
    580                log.debug("fromNative(): failure: ", ex);
    581                datatypeClass = CLASS_NO_CLASS;
    582            }
    583
    584            datatypeOrder = (torder == HDF5Constants.H5T_ORDER_BE) ? ORDER_BE : ORDER_LE;
    585
    586            try {
    587                isUchar = H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_UCHAR);
    588                isChar = (H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_CHAR) || isUchar);
    589            }
    590            catch (Exception ex) {
    591                log.debug("fromNative(): native char type failure: ", ex);
    592            }
    593
    594            datatypeSign = NSGN; // default
    595            if (nativeClass == HDF5Constants.H5T_ARRAY) {
    596                long tmptid = -1;
    597                datatypeClass = CLASS_ARRAY;
    598                try {
    599                    int ndims = H5.H5Tget_array_ndims(tid);
    600                    arrayDims = new long[ndims];
    601                    H5.H5Tget_array_dims(tid, arrayDims);
    602                    tmptid = H5.H5Tget_super(tid);
    603                    baseType = new H5Datatype(tmptid);
    604                    datatypeSign = baseType.getDatatypeSign();
    605                }
    606                catch (Exception ex) {
    607                    log.debug("fromNative(): array type failure: ", ex);
    608                }
    609                finally {
    610                    close(tmptid);
    611                }
    612                log.trace("fromNative(): array type finish");
    613            }
    614            else if (nativeClass == HDF5Constants.H5T_COMPOUND) {
    615                datatypeClass = CLASS_COMPOUND;
    616
    617                try {
    618                    int nMembers = H5.H5Tget_nmembers(tid);
    619                    compoundMemberNames = new Vector<>(nMembers);
    620                    compoundMemberTypes = new Vector<>(nMembers);
    621                    compoundMemberOffsets = new Vector<>(nMembers);
    622                    log.trace("fromNative(): compound type nMembers={} start", nMembers);
    623
    624                    for (int i = 0; i < nMembers; i++) {
    625                        String memberName = H5.H5Tget_member_name(tid, i);
    626                        log.trace("fromNative(): compound type [{}] name={} start", i, memberName);
    627                        long memberOffset = H5.H5Tget_member_offset(tid, i);
    628                        long memberID = -1;
    629                        H5Datatype membertype = null;
    630                        try {
    631                            memberID = H5.H5Tget_member_type(tid, i);
    632                            membertype = new H5Datatype(memberID, this);
    633                        }
    634                        catch (Exception ex1) {
    635                            log.debug("fromNative(): compound type failure: ", ex1);
    636                        }
    637                        finally {
    638                            close(memberID);
    639                        }
    640
    641                        compoundMemberNames.add(i, memberName);
    642                        compoundMemberOffsets.add(i, memberOffset);
    643                        compoundMemberTypes.add(i, membertype);
    644                        log.trace("fromNative(): compound type [{}] name={} finish", i, memberName);
    645                    }
    646                }
    647                catch (HDF5LibraryException ex) {
    648                    log.debug("fromNative(): compound type failure: ", ex);
    649                }
    650                log.trace("fromNative(): compound type finish");
    651            }
    652            else if (nativeClass == HDF5Constants.H5T_INTEGER) {
    653                datatypeClass = CLASS_INTEGER;
    654                try {
    655                    log.trace("fromNative(): integer type");
    656                    int tsign = H5.H5Tget_sign(tid);
    657                    datatypeSign = (tsign == HDF5Constants.H5T_SGN_NONE) ? SIGN_NONE : SIGN_2;
    658                }
    659                catch (Exception ex) {
    660                    log.debug("fromNative(): int type failure: ", ex);
    661                }
    662            }
    663            else if (nativeClass == HDF5Constants.H5T_FLOAT) {
    664                datatypeClass = CLASS_FLOAT;
    665            }
    666            else if (isChar) {
    667                datatypeClass = CLASS_CHAR;
    668                datatypeSign = (isUchar) ? SIGN_NONE : SIGN_2;
    669            }
    670            else if (nativeClass == HDF5Constants.H5T_STRING) {
    671                datatypeClass = CLASS_STRING;
    672                try {
    673                    is_VLEN = H5.H5Tdetect_class(tid, HDF5Constants.H5T_VLEN) || is_variable_str;
    674                    log.trace("fromNative(): var str type={}", is_VLEN);
    675                    nativeStrPad = H5.H5Tget_strpad(tid);
    676                }
    677                catch (Exception ex) {
    678                    log.debug("fromNative(): var str type failure: ", ex);
    679                }
    680            }
    681            else if (nativeClass == HDF5Constants.H5T_REFERENCE) {
    682                datatypeClass = CLASS_REFERENCE;
    683                log.trace("fromNative(): reference type");
    684                try {
    685                    is_reg_ref = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG);
    686                }
    687                catch (Exception ex) {
    688                    log.debug("fromNative(): H5T_STD_REF_DSETREG: ", ex);
    689                }
    690                try {
    691                    is_ref_obj = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_OBJ);
    692                }
    693                catch (Exception ex) {
    694                    log.debug("fromNative(): H5T_STD_REF_OBJ: ", ex);
    695                }
    696            }
    697            else if (nativeClass == HDF5Constants.H5T_ENUM) {
    698                datatypeClass = CLASS_ENUM;
    699                long tmptid = -1;
    700                long basetid = -1;
    701                try {
    702                    log.trace("fromNative(): enum type");
    703                    basetid = H5.H5Tget_super(tid);
    704                    tmptid = basetid;
    705                    basetid = H5.H5Tget_native_type(tmptid);
    706                    log.trace("fromNative(): enum type basetid={}", basetid);
    707                    if (basetid >= 0) {
    708                        baseType = new H5Datatype(tmptid, this);
    709                        datatypeSign = baseType.getDatatypeSign();
    710                    }
    711                }
    712                catch (Exception ex) {
    713                    log.debug("fromNative(): enum type failure: ", ex);
    714                }
    715                finally {
    716                    close(tmptid);
    717                    close(basetid);
    718                }
    719                try {
    720                    int enumMemberCount = H5.H5Tget_nmembers(tid);
    721                    String name = null;
    722                    String enumStr = null;
    723                    byte[] val = new byte[(int)tsize];
    724                    enumMembers = new HashMap<>();
    725                    for (int i = 0; i < enumMemberCount; i++) {
    726                        name = H5.H5Tget_member_name(tid, i);
    727                        H5.H5Tget_member_value(tid, i, val);
    728                        switch ((int)H5.H5Tget_size(tid)) {
    729                            case 1:
    730                                enumStr = Byte.toString((HDFNativeData.byteToByte(val[0]))[0]);
    731                                break;
    732                            case 2:
    733                                enumStr = Short.toString((HDFNativeData.byteToShort(val))[0]);
    734                                break;
    735                            case 4:
    736                                enumStr = Integer.toString((HDFNativeData.byteToInt(val))[0]);
    737                                break;
    738                            case 8:
    739                                enumStr = Long.toString((HDFNativeData.byteToLong(val))[0]);
    740                                break;
    741                            default:
    742                                enumStr = "-1";
    743                                break;
    744                        }
    745                        enumMembers.put(enumStr, name);
    746                    }
    747                }
    748                catch (Exception ex) {
    749                    log.debug("fromNative(): enum type failure: ", ex);
    750                }
    751            }
    752            else if (nativeClass == HDF5Constants.H5T_VLEN) {
    753                long tmptid = -1;
    754                datatypeClass = CLASS_VLEN;
    755                is_VLEN = true;
    756                try {
    757                    log.trace("fromNative(): vlen type");
    758                    tmptid = H5.H5Tget_super(tid);
    759                    baseType = new H5Datatype(tmptid);
    760                    datatypeSign = baseType.getDatatypeSign();
    761                }
    762                catch (Exception ex) {
    763                    log.debug("fromNative(): vlen type failure: ", ex);
    764                }
    765                finally {
    766                    close(tmptid);
    767                }
    768            }
    769            else if (nativeClass == HDF5Constants.H5T_BITFIELD) {
    770                datatypeClass = CLASS_BITFIELD;
    771            }
    772            else if (nativeClass == HDF5Constants.H5T_OPAQUE) {
    773                datatypeClass = CLASS_OPAQUE;
    774
    775                try {
    776                    opaqueTag = H5.H5Tget_tag(tid);
    777                }
    778                catch (Exception ex) {
    779                    log.debug("fromNative(): opaque type tag retrieval failed: ", ex);
    780                    opaqueTag = null;
    781                }
    782            }
    783            else {
    784                log.debug("fromNative(): datatypeClass is unknown");
    785            }
    786
    787            datatypeSize = (is_VLEN && !is_variable_str) ? HDF5Constants.H5T_VL_T : tsize;
    788        }
    789        log.trace("fromNative(): datatypeClass={} baseType={} datatypeSize={}", datatypeClass, baseType, datatypeSize);
    790        log.trace("fromNative(): finish");
    791    }
    792
    793    /**
    794     * @param tid
    795     *            the datatype identification disk.
    796     *
    797     * @return the memory datatype identifier if successful, and negative otherwise.
    798     */
    799    public static long toNative(long tid) {
    800        // data type information
    801        log.trace("toNative(): tid={} start", tid);
    802        long native_id = -1;
    803
    804        try {
    805            native_id = H5.H5Tget_native_type(tid);
    806        }
    807        catch (Exception ex) {
    808            log.debug("toNative(): H5Tget_native_type(tid {}) failure: ", tid, ex);
    809        }
    810
    811        try {
    812            if (H5.H5Tis_variable_str(tid))
    813                H5.H5Tset_size(native_id, HDF5Constants.H5T_VARIABLE);
    814        }
    815        catch (Exception ex) {
    816            log.debug("toNative(): var str type size failure: ", ex);
    817        }
    818
    819        return native_id;
    820    }
    821
    822    /*
    823     * (non-Javadoc)
    824     *
    825     * @see hdf.object.Datatype#createNative()
    826     */
    827    @SuppressWarnings("rawtypes")
    828    @Override
    829    public long createNative() {
    830        log.trace("createNative(): start");
    831
    832        long tid = -1;
    833        long tmptid = -1;
    834
    835        if (isNamed) {
    836            try {
    837                tid = H5.H5Topen(getFID(), getPath() + getName(), HDF5Constants.H5P_DEFAULT);
    838            }
    839            catch (Exception ex) {
    840                log.debug("createNative(): name {} H5Topen failure: ", getPath() + getName(), ex);
    841            }
    842        }
    843
    844        if (tid >= 0) {
    845            log.trace("createNative(): tid >= 0");
    846            log.trace("createNative(): finish");
    847            return tid;
    848        }
    849
    850        // figure the datatype
    851        try {
    852            log.trace("createNative(): datatypeClass={} datatypeSize={} baseType={}", datatypeClass, datatypeSize, baseType);
    853            switch (datatypeClass) {
    854                case CLASS_ARRAY:
    855                    if (baseType != null) {
    856                        if ((tmptid = baseType.createNative()) >= 0) {
    857                            try {
    858                                tid = H5.H5Tarray_create(tmptid, arrayDims.length, arrayDims);
    859                            }
    860                            finally {
    861                                close(tmptid);
    862                            }
    863                        }
    864                    }
    865                    else {
    866                        log.debug("createNative(): CLASS_ARRAY base type is NULL");
    867                    }
    868                    break;
    869                case CLASS_COMPOUND:
    870                    try {
    871                        tid = H5.H5Tcreate(CLASS_COMPOUND, datatypeSize);
    872
    873                        for (int i = 0; i < compoundMemberTypes.size(); i++) {
    874                            H5Datatype memberType = null;
    875                            String memberName = null;
    876                            long memberOffset = -1;
    877
    878                            try {
    879                                memberType = (H5Datatype) compoundMemberTypes.get(i);
    880                            }
    881                            catch (Exception ex) {
    882                                log.debug("createNative(): get compound member[{}] type failure: ", i, ex);
    883                                memberType = null;
    884                            }
    885
    886                            try {
    887                                memberName = compoundMemberNames.get(i);
    888                            }
    889                            catch (Exception ex) {
    890                                log.debug("createNative(): get compound member[{}] name failure: ", i, ex);
    891                                memberName = null;
    892                            }
    893
    894                            try {
    895                                memberOffset = compoundMemberOffsets.get(i);
    896                            }
    897                            catch (Exception ex) {
    898                                log.debug("createNative(): get compound member[{}] offset failure: ", i, ex);
    899                                memberOffset = -1;
    900                            }
    901
    902                            long memberID = -1;
    903                            try {
    904                                memberID = memberType.createNative();
    905                                log.trace("createNative(): {} member[{}] with offset={} ID={}: ", memberName, i, memberOffset, memberID);
    906
    907                                H5.H5Tinsert(tid, memberName, memberOffset, memberID);
    908                            }
    909                            catch (Exception ex) {
    910                                log.debug("createNative(): compound type member[{}] insertion failure: ", i, ex);
    911                            }
    912                            finally {
    913                                close(memberID);
    914                            }
    915                        }
    916                    }
    917                    catch (Exception ex) {
    918                        log.debug("createNative(): failure: ", ex);
    919                    }
    920                    break;
    921                case CLASS_INTEGER:
    922                case CLASS_ENUM:
    923                    if (datatypeSize == 1) {
    924                        log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT8");
    925                        tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8);
    926                    }
    927                    else if (datatypeSize == 2) {
    928                        log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT16");
    929                        tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT16);
    930                    }
    931                    else if (datatypeSize == 4) {
    932                        log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT32");
    933                        tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32);
    934                    }
    935                    else if (datatypeSize == 8) {
    936                        log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT64");
    937                        tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT64);
    938                    }
    939                    else {
    940                        log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT");
    941                        tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT);
    942                    }
    943
    944                    if (datatypeOrder == Datatype.ORDER_BE) {
    945                        log.trace("createNative(): CLASS_INT-ENUM order is H5T_ORDER_BE");
    946                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
    947                    }
    948                    else if (datatypeOrder == Datatype.ORDER_LE) {
    949                        log.trace("createNative(): CLASS_INT-ENUM order is H5T_ORDER_LE");
    950                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
    951                    }
    952
    953                    if (datatypeSign == Datatype.SIGN_NONE) {
    954                        log.trace("createNative(): CLASS_INT-ENUM is H5T_SGN_NONE");
    955                        H5.H5Tset_sign(tid, HDF5Constants.H5T_SGN_NONE);
    956                    }
    957                    break;
    958                case CLASS_FLOAT:
    959                    tid = H5.H5Tcopy((datatypeSize == 8) ? HDF5Constants.H5T_NATIVE_DOUBLE : HDF5Constants.H5T_NATIVE_FLOAT);
    960
    961                    if (datatypeOrder == Datatype.ORDER_BE) {
    962                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
    963                    }
    964                    else if (datatypeOrder == Datatype.ORDER_LE) {
    965                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
    966                    }
    967
    968                    break;
    969                case CLASS_CHAR:
    970                    tid = H5.H5Tcopy((datatypeSign == Datatype.SIGN_NONE) ? HDF5Constants.H5T_NATIVE_UCHAR : HDF5Constants.H5T_NATIVE_CHAR);
    971                    break;
    972                case CLASS_STRING:
    973                    tid = H5.H5Tcopy(HDF5Constants.H5T_C_S1);
    974                    H5.H5Tset_size(tid, (is_VLEN || datatypeSize < 0) ? HDF5Constants.H5T_VARIABLE : datatypeSize);
    975
    976                    log.trace("createNative(): isVlenStr={}", is_VLEN);
    977
    978                    H5.H5Tset_strpad(tid, (nativeStrPad >= 0) ? nativeStrPad : HDF5Constants.H5T_STR_NULLTERM);
    979
    980                    break;
    981                case CLASS_REFERENCE:
    982                    long obj_ref_type_size = H5.H5Tget_size(HDF5Constants.H5T_STD_REF_OBJ);
    983                    tid = H5.H5Tcopy((datatypeSize > obj_ref_type_size) ? HDF5Constants.H5T_STD_REF_DSETREG : HDF5Constants.H5T_STD_REF_OBJ);
    984                    break;
    985                case CLASS_VLEN:
    986                    if (baseType != null) {
    987                        if ((tmptid = baseType.createNative()) >= 0) {
    988                            try {
    989                                tid = H5.H5Tvlen_create(tmptid);
    990                            }
    991                            finally {
    992                                close(tmptid);
    993                            }
    994                        }
    995                    }
    996                    else {
    997                        log.debug("createNative(): CLASS_VLEN base type is NULL");
    998                    }
    999                    break;
    1000                case CLASS_BITFIELD:
    1001                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B8);
    1002
    1003                    log.trace("createNative(): CLASS_BITFIELD size is " + datatypeSize);
    1004                    if (datatypeSize > 0) H5.H5Tset_size(tid, datatypeSize);
    1005
    1006                    if (datatypeOrder == Datatype.ORDER_BE) {
    1007                        log.trace("createNative(): CLASS_BITFIELD-OPAQUE order is H5T_ORDER_BE");
    1008                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
    1009                    }
    1010                    else if (datatypeOrder == Datatype.ORDER_LE) {
    1011                        log.trace("createNative(): CLASS_BITFIELD-OPAQUE order is H5T_ORDER_LE");
    1012                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
    1013                    }
    1014
    1015                    break;
    1016                case CLASS_OPAQUE:
    1017                    tid = H5.H5Tcreate(HDF5Constants.H5T_OPAQUE, datatypeSize);
    1018
    1019                    if (opaqueTag != null) {
    1020                        H5.H5Tset_tag(tid, opaqueTag);
    1021                    }
    1022
    1023                    break;
    1024                default:
    1025                    log.debug("createNative(): Unknown class");
    1026                    break;
    1027            } // switch (tclass)
    1028        }
    1029        catch (Exception ex) {
    1030            log.debug("createNative(): Error figuring the datatype: ", ex);
    1031            tid = -1;
    1032        }
    1033
    1034        // set up enum members
    1035        if (datatypeClass == CLASS_ENUM) {
    1036            long ptid = tid;
    1037            try {
    1038                tid = H5.H5Tenum_create(ptid);
    1039                datatypeSize = H5.H5Tget_size(tid);
    1040            }
    1041            catch (Exception ex) {
    1042                log.debug("createNative(): create members failure: ", ex);
    1043                tid = -1;
    1044            }
    1045
    1046            try {
    1047                String memstr, memname;
    1048                byte[] memval = null;
    1049                if (datatypeSize == 1) {
    1050                    memval = HDFNativeData.byteToByte(new Byte((byte) 0));
    1051                }
    1052                else if (datatypeSize == 2) {
    1053                    memval = HDFNativeData.shortToByte(new Short((short) 0));
    1054                }
    1055                else if (datatypeSize == 4) {
    1056                    memval = HDFNativeData.intToByte(new Integer(0));
    1057                }
    1058                else if (datatypeSize == 8) {
    1059                    memval = HDFNativeData.longToByte(new Long(0));
    1060                }
    1061
    1062                // using "0" and "1" as default
    1063                if (enumMembers == null) {
    1064                    enumMembers = new HashMap<>();
    1065                    enumMembers.put("1", "0");
    1066                    enumMembers.put("2", "1");
    1067                    log.trace("createNative(): default string");
    1068                }
    1069                Iterator entries = enumMembers.entrySet().iterator();
    1070                while (entries.hasNext()) {
    1071                    Entry thisEntry = (Entry) entries.next();
    1072                    memstr = (String) thisEntry.getKey();
    1073                    memname = (String) thisEntry.getValue();
    1074
    1075                    if (datatypeSize == 1) {
    1076                        log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT8");
    1077                        Byte tval = Byte.parseByte(memstr);
    1078                        memval = HDFNativeData.byteToByte(tval);
    1079                    }
    1080                    else if (datatypeSize == 2) {
    1081                        log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT16");
    1082                        Short tval = Short.parseShort(memstr);
    1083                        memval = HDFNativeData.shortToByte(tval);
    1084                    }
    1085                    else if (datatypeSize == 4) {
    1086                        log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT32");
    1087                        Integer tval = Integer.parseInt(memstr);
    1088                        memval = HDFNativeData.intToByte(tval);
    1089                    }
    1090                    else if (datatypeSize == 8) {
    1091                        log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT64");
    1092                        Long tval = Long.parseLong(memstr);
    1093                        memval = HDFNativeData.longToByte(tval);
    1094                    }
    1095                    else {
    1096                        log.debug("createNative(): enum datatypeSize incorrect");
    1097                    }
    1098                    log.trace("createNative(): H5Tenum_insert {} {}", memname, memval);
    1099                    H5.H5Tenum_insert(tid, memname, memval);
    1100                }
    1101            }
    1102            catch (Exception ex) {
    1103                log.debug("createNative(): set up enum members failure: ", ex);
    1104            }
    1105            finally {
    1106                close(ptid);
    1107            }
    1108        } // if (datatypeClass == CLASS_ENUM) {
    1109
    1110        try {
    1111            tmptid = tid;
    1112            tid = H5.H5Tget_native_type(tmptid);
    1113        }
    1114        catch (HDF5Exception ex) {
    1115            log.debug("createNative(): H5Tget_native_type{} failure: ", tmptid, ex);
    1116        }
    1117        finally {
    1118            close(tmptid);
    1119        }
    1120
    1121        return tid;
    1122    }
    1123
    1124    /**
    1125     * Allocates a one-dimensional array of byte, short, int, long, float, double,
    1126     * or String to store data in memory.
    1127     *
    1128     * For example,
    1129     *
    1130     * <pre>
    1131     * long tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32);
    1132     * int[] data = (int[]) allocateArray(100);
    1133     * </pre>
    1134     *
    1135     * returns a 32-bit integer array of size 100.
    1136     *
    1137     * @param spaceSize
    1138     *            the total number of data points of the array.
    1139     *
    1140     * @return the array object if successful; otherwise, return null.
    1141     *
    1142     * @throws OutOfMemoryError
    1143     *             If there is a failure.
    1144     */
    1145    public Object allocateArray(int spaceSize) throws OutOfMemoryError {
    1146        log.trace("allocateArray(): start: spaceSize={}", spaceSize);
    1147        Object data = null;
    1148
    1149        if (spaceSize < 0) {
    1150            log.debug("allocateArray(): spaceSize < 0");
    1151            log.trace("allocateArray(): finish");
    1152            return null;
    1153        }
    1154
    1155        // Scalar members have dimensionality zero, i.e. size =0
    1156        // what can we do about it, set the size to 1
    1157        if (spaceSize == 0) {
    1158            spaceSize = 1;
    1159        }
    1160
    1161        log.trace("allocateArray(): tclass={} : tsize={}", nativeClass, datatypeSize);
    1162
    1163        if (is_variable_str || is_VLEN || is_reg_ref) {
    1164            log.trace("allocateArray(): is_variable_str={} || isVL={} || is_reg_ref={}", is_variable_str, is_VLEN, is_reg_ref);
    1165            data = new String[spaceSize];
    1166            for (int i = 0; i < spaceSize; i++) {
    1167                ((String[]) data)[i] = "";
    1168            }
    1169        }
    1170        else if (nativeClass == HDF5Constants.H5T_INTEGER) {
    1171            log.trace("allocateArray(): class.H5T_INTEGER={}", nativeClass);
    1172            if (datatypeSize == 1) {
    1173                data = new byte[spaceSize];
    1174            }
    1175            else if (datatypeSize == 2) {
    1176                data = new short[spaceSize];
    1177            }
    1178            else if (datatypeSize == 4) {
    1179                data = new int[spaceSize];
    1180            }
    1181            else if (datatypeSize == 8) {
    1182                data = new long[spaceSize];
    1183            }
    1184        }
    1185        else if (nativeClass == HDF5Constants.H5T_ENUM) {
    1186            log.trace("allocateArray(): class.H5T_ENUM={}", nativeClass);
    1187            if (baseType != null)
    1188                data = ((H5Datatype) baseType).allocateArray(spaceSize);
    1189            else
    1190                data = new byte[(int) (spaceSize * datatypeSize)];
    1191        }
    1192        else if (nativeClass == HDF5Constants.H5T_COMPOUND) {
    1193            log.trace("allocateArray(): class.H5T_COMPOUND={}", nativeClass);
    1194            if (baseType != null)
    1195                data = ((H5Datatype) baseType).allocateArray((spaceSize));
    1196            else
    1197                data = new byte[(int) (spaceSize * datatypeSize)];
    1198        }
    1199        else if (nativeClass == HDF5Constants.H5T_FLOAT) {
    1200            log.trace("allocateArray(): class.H5T_FLOAT={}", nativeClass);
    1201            if (datatypeSize == 4) {
    1202                data = new float[spaceSize];
    1203            }
    1204            else if (datatypeSize == 8) {
    1205                data = new double[spaceSize];
    1206            }
    1207        }
    1208        else if ((nativeClass == HDF5Constants.H5T_STRING) || (nativeClass == HDF5Constants.H5T_REFERENCE)) {
    1209            log.trace("allocateArray(): class.H5T_STRING || H5T_REFERENCE={}", nativeClass);
    1210            data = new byte[(int) (spaceSize * datatypeSize)];
    1211        }
    1212        else if (nativeClass == HDF5Constants.H5T_ARRAY) {
    1213            // use the base datatype to define the array
    1214            try {
    1215                log.trace("allocateArray(): ArrayRank={}", arrayDims.length);
    1216                int asize = spaceSize;
    1217                for (int j = 0; j < arrayDims.length; j++) {
    1218                    log.trace("allocateArray(): ArrayRank={} : dims[{}]={}", arrayDims.length, j, arrayDims[j]);
    1219                    asize *= arrayDims[j];
    1220                }
    1221                log.trace("allocateArray(): class.H5T_ARRAY={} : members={} : asize={} : datatypeSize={}", nativeClass, arrayDims.length, asize, datatypeSize);
    1222
    1223                if (baseType != null) {
    1224                    // data = new byte[(int) (size * asize * datatypeSize)];
    1225                    data = ((H5Datatype) baseType).allocateArray(asize);
    1226                }
    1227            }
    1228            catch (Exception ex) {
    1229                log.debug("allocateArray(): H5T_ARRAY class failure: ", ex);
    1230            }
    1231        }
    1232        else if ((nativeClass == HDF5Constants.H5T_OPAQUE) || (nativeClass == HDF5Constants.H5T_BITFIELD)) {
    1233            log.trace("allocateArray(): class.H5T_OPAQUE || H5T_BITFIELD={}", nativeClass);
    1234            data = new byte[(int) (spaceSize * datatypeSize)];
    1235        }
    1236        else {
    1237            log.debug("allocateArray(): class.????={}", nativeClass);
    1238            data = null;
    1239        }
    1240
    1241        return data;
    1242    }
    1243
    1244    /**
    1245     * Returns the size (in bytes) of a given datatype identifier.
    1246     * <p>
    1247     * It basically just calls H5Tget_size(tid).
    1248     *
    1249     * @param tid
    1250     *            The datatype identifier.
    1251     *
    1252     * @return The size of the datatype in bytes.
    1253     *
    1254     * @see hdf.hdf5lib.H5#H5Tget_size(long)
    1255     */
    1256    public static final long getDatatypeSize(long tid) {
    1257        // data type information
    1258        long tsize = -1;
    1259
    1260        try {
    1261            tsize = H5.H5Tget_size(tid);
    1262        }
    1263        catch (Exception ex) {
    1264            tsize = -1;
    1265        }
    1266
    1267        return tsize;
    1268    }
    1269
    1270    /*
    1271     * (non-Javadoc)
    1272     *
    1273     * @see hdf.object.Datatype#getDescription()
    1274     */
    1275    @Override
    1276    public String getDescription() {
    1277        log.trace("getDescription(): start");
    1278
    1279        if (datatypeDescription != null) {
    1280            log.trace("getDescription(): finish");
    1281            return datatypeDescription;
    1282        }
    1283
    1284        String description = null;
    1285        long tid = -1;
    1286
    1287        switch (datatypeClass) {
    1288            case CLASS_CHAR:
    1289                description = "8-bit " + (isUnsigned() ? "unsigned " : "") + "integer";
    1290                break;
    1291            case CLASS_INTEGER:
    1292                description = String.valueOf(datatypeSize * 8) + "-bit " + (isUnsigned() ? "unsigned " : "") + "integer";
    1293                break;
    1294            case CLASS_FLOAT:
    1295                description = String.valueOf(datatypeSize * 8) + "-bit floating-point";
    1296                break;
    1297            case CLASS_STRING:
    1298                description = "String, length = " + (isVarStr() ? "variable" : datatypeSize);
    1299
    1300                try {
    1301                    tid = createNative();
    1302                    if (tid >= 0) {
    1303                        String strPadType;
    1304                        int strPad = H5.H5Tget_strpad(tid);
    1305
    1306                        if (strPad == HDF5Constants.H5T_STR_NULLTERM)
    1307                            strPadType = "H5T_STR_NULLTERM";
    1308                        else if (strPad == HDF5Constants.H5T_STR_NULLPAD)
    1309                            strPadType = "H5T_STR_NULLPAD";
    1310                        else if (strPad == HDF5Constants.H5T_STR_SPACEPAD)
    1311                            strPadType = "H5T_STR_SPACEPAD";
    1312                        else
    1313                            strPadType = null;
    1314
    1315                        if (strPadType != null)
    1316                            description += ", string padding = " + strPadType;
    1317                    }
    1318                    else {
    1319                        log.debug("createNative() failure");
    1320                    }
    1321                }
    1322                catch (Exception ex) {
    1323                    log.debug("H5Tget_strpad failure: ", ex);
    1324                }
    1325                finally {
    1326                    close(tid);
    1327                }
    1328                break;
    1329            case CLASS_BITFIELD:
    1330                description = String.valueOf(datatypeSize * 8) + "-bit bitfield";
    1331                break;
    1332            case CLASS_OPAQUE:
    1333                description = String.valueOf(datatypeSize) + "-byte Opaque";
    1334
    1335                if (opaqueTag != null) {
    1336                    description += ", tag = " + opaqueTag;
    1337                }
    1338
    1339                break;
    1340            case CLASS_COMPOUND:
    1341                description = "Compound";
    1342
    1343                if ((compoundMemberTypes != null) && (compoundMemberTypes.size() > 0)) {
    1344                    Iterator<String> member_names = null;
    1345                    Iterator<Datatype> member_types = compoundMemberTypes.iterator();
    1346
    1347                    if (compoundMemberNames != null)
    1348                        member_names = compoundMemberNames.iterator();
    1349
    1350                    description += " {";
    1351
    1352                    while (member_types.hasNext()) {
    1353                        if (member_names != null && member_names.hasNext()) {
    1354                            description += member_names.next() + " = ";
    1355                        }
    1356
    1357                        description += member_types.next().getDescription();
    1358
    1359                        if (member_types.hasNext())
    1360                            description += ", ";
    1361                    }
    1362
    1363                    description += "}";
    1364                }
    1365
    1366                break;
    1367            case CLASS_REFERENCE:
    1368                description = "Reference";
    1369
    1370                try {
    1371                    boolean is_reg_ref = false;
    1372
    1373                    tid = createNative();
    1374                    if (tid >= 0) {
    1375                        is_reg_ref = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG);
    1376
    1377                        if (is_reg_ref) {
    1378                            description = "Dataset region reference";
    1379                        }
    1380                        else {
    1381                            description = "Object reference";
    1382                        }
    1383                    }
    1384                }
    1385                catch (Exception ex) {
    1386                    log.debug("H5.H5Tequal failure: ", ex);
    1387                }
    1388                finally {
    1389                    close(tid);
    1390                }
    1391
    1392                break;
    1393            case CLASS_ENUM:
    1394                description = String.valueOf(datatypeSize * 8) + "-bit enum";
    1395
    1396                String members = getEnumMembersAsString();
    1397                if (members != null)
    1398                    description += " (" + members + ")";
    1399
    1400                break;
    1401            case CLASS_VLEN:
    1402                description = "Variable-length";
    1403
    1404                if (baseType != null) {
    1405                    description += " of " + baseType.getDescription();
    1406                }
    1407
    1408                break;
    1409            case CLASS_ARRAY:
    1410                description = "Array";
    1411
    1412                if (baseType != null) {
    1413                    description += " of " + baseType.getDescription();
    1414                }
    1415
    1416                if (arrayDims != null) {
    1417                    description += " [";
    1418                    for (int i = 0; i < arrayDims.length; i++) {
    1419                        description += arrayDims[i];
    1420                        if (i < arrayDims.length - 1)
    1421                            description += " x ";
    1422                    }
    1423                    description += "]";
    1424                }
    1425
    1426                break;
    1427            default:
    1428                description = "Unknown";
    1429                break;
    1430        }
    1431
    1432        log.trace("getDescription(): finish");
    1433        return description;
    1434    }
    1435
    1436    /**
    1437     * Checks if a datatype specified by the identifier is an unsigned integer.
    1438     *
    1439     * @param tid
    1440     *            the datatype ID to be checked.
    1441     *
    1442     * @return true is the datatype is an unsigned integer; otherwise returns false.
    1443     */
    1444    public static final boolean isUnsigned(long tid) {
    1445        boolean unsigned = false;
    1446
    1447        if (tid >= 0) {
    1448            try {
    1449                int tclass = H5.H5Tget_class(tid);
    1450                log.trace("isUnsigned(): tclass = {}", tclass);
    1451                if (tclass != HDF5Constants.H5T_FLOAT && tclass != HDF5Constants.H5T_STRING
    1452                        && tclass != HDF5Constants.H5T_REFERENCE && tclass != HDF5Constants.H5T_BITFIELD
    1453                        && tclass != HDF5Constants.H5T_OPAQUE && tclass != HDF5Constants.H5T_VLEN
    1454                        && tclass != HDF5Constants.H5T_COMPOUND && tclass != HDF5Constants.H5T_ARRAY) {
    1455                    int tsign = H5.H5Tget_sign(tid);
    1456                    if (tsign == HDF5Constants.H5T_SGN_NONE) {
    1457                        unsigned = true;
    1458                    }
    1459                    else {
    1460                        log.trace("isUnsigned(): not unsigned");
    1461                    }
    1462                }
    1463                else {
    1464                    log.trace("isUnsigned(): tclass not integer type");
    1465                }
    1466            }
    1467            catch (Exception ex) {
    1468                log.debug("isUnsigned(): Datatype {} failure", tid, ex);
    1469                unsigned = false;
    1470            }
    1471        }
    1472        else {
    1473            log.trace("isUnsigned(): not a valid datatype");
    1474        }
    1475
    1476        return unsigned;
    1477    }
    1478
    1479    /*
    1480     * (non-Javadoc)
    1481     *
    1482     * @see hdf.object.Datatype#getMetadata()
    1483     */
    1484    @Override
    1485    public List<Attribute> getMetadata() throws HDF5Exception {
    1486        return this.getMetadata(fileFormat.getIndexType(null), fileFormat.getIndexOrder(null));
    1487    }
    1488
    1489    /*
    1490     * (non-Javadoc)
    1491     *
    1492     * @see hdf.object.DataFormat#getMetadata(int...)
    1493     */
    1494    public List<Attribute> getMetadata(int... attrPropList) throws HDF5Exception {
    1495        log.trace("getMetadata(): start");
    1496        // load attributes first
    1497        if (attributeList == null) {
    1498            int indxType = fileFormat.getIndexType(null);
    1499            int order = fileFormat.getIndexOrder(null);
    1500
    1501            if (attrPropList.length > 0) {
    1502                indxType = attrPropList[0];
    1503                if (attrPropList.length > 1) {
    1504                    order = attrPropList[1];
    1505                }
    1506            }
    1507
    1508            try {
    1509                attributeList = H5File.getAttribute(this, indxType, order);
    1510            }
    1511            catch (Exception ex) {
    1512                log.debug("getMetadata(): H5File.getAttribute failure: ", ex);
    1513            }
    1514        } // if (attributeList == null)
    1515
    1516        try {
    1517            this.linkTargetObjName = H5File.getLinkTargetName(this);
    1518        }
    1519        catch (Exception ex) {
    1520            log.debug("getMetadata(): H5File.linkTargetObjName failure: ", ex);
    1521        }
    1522
    1523        log.trace("getMetadata(): finish");
    1524        return attributeList;
    1525    }
    1526
    1527    /*
    1528     * (non-Javadoc)
    1529     *
    1530     * @see hdf.object.Datatype#writeMetadata(java.lang.Object)
    1531     */
    1532    @Override
    1533    public void writeMetadata(Object info) throws Exception {
    1534        log.trace("writeMetadata(): start");
    1535
    1536        // only attribute metadata is supported.
    1537        if (!(info instanceof Attribute)) {
    1538            log.debug("writeMetadata(): Object not an Attribute");
    1539            log.trace("writeMetadata(): finish");
    1540            return;
    1541        }
    1542
    1543        boolean attrExisted = false;
    1544        Attribute attr = (Attribute) info;
    1545
    1546        if (attributeList == null) {
    1547            this.getMetadata();
    1548        }
    1549
    1550        if (attributeList != null)
    1551            attrExisted = attributeList.contains(attr);
    1552
    1553        getFileFormat().writeAttribute(this, attr, attrExisted);
    1554
    1555        // add the new attribute into attribute list
    1556        if (!attrExisted) {
    1557            attributeList.add(attr);
    1558            nAttributes = attributeList.size();
    1559        }
    1560        log.trace("writeMetadata(): finish");
    1561    }
    1562
    1563    /*
    1564     * (non-Javadoc)
    1565     *
    1566     * @see hdf.object.Datatype#removeMetadata(java.lang.Object)
    1567     */
    1568    @Override
    1569    public void removeMetadata(Object info) throws HDF5Exception {
    1570        log.trace("removeMetadata(): start");
    1571
    1572        // only attribute metadata is supported.
    1573        if (!(info instanceof Attribute)) {
    1574            log.debug("removeMetadata(): Object not an attribute");
    1575            log.trace("removeMetadata(): finish");
    1576            return;
    1577        }
    1578
    1579        Attribute attr = (Attribute) info;
    1580        long tid = open();
    1581        try {
    1582            H5.H5Adelete(tid, attr.getName());
    1583            List<Attribute> attrList = getMetadata();
    1584            attrList.remove(attr);
    1585            nAttributes = attributeList.size();
    1586        }
    1587        catch (Exception ex) {
    1588            log.debug("removeMetadata(): ", ex);
    1589        }
    1590        finally {
    1591            close(tid);
    1592        }
    1593        log.trace("removeMetadata(): finish");
    1594    }
    1595
    1596    @Override
    1597    public void setName(String newName) throws Exception {
    1598        H5File.renameObject(this, newName);
    1599        super.setName(newName);
    1600    }
    1601
    1602    @Override
    1603    public boolean isText() {
    1604        return (datatypeClass == Datatype.CLASS_STRING);
    1605    }
    1606
    1607    public boolean isRefObj() {
    1608        return is_ref_obj;
    1609    }
    1610
    1611    public boolean isRegRef() {
    1612        return is_reg_ref;
    1613    }
    1614
    1615    public int getNativeStrPad() {
    1616        return nativeStrPad;
    1617    }
    1618
    1619    /**
    1620     * Extracts compound information into flat structure.
    1621     * <p>
    1622     * For example, compound datatype "nest" has {nest1{a, b, c}, d, e} then extractCompoundInfo() will
    1623     * put the names of nested compound fields into a flat list as
    1624     *
    1625     * <pre>
    1626     * nest.nest1.a
    1627     * nest.nest1.b
    1628     * nest.nest1.c
    1629     * nest.d
    1630     * nest.e
    1631     * </pre>
    1632     *
    1633     * @param name
    1634     *            the name of the compound datatype
    1635     * @param names
    1636     *            the list to store the member names of the compound datatype
    1637     * @param flatListTypes
    1638     *            the list to store the nested member names of the compound datatype
    1639     */
    1640    public void extractCompoundInfo(String name, List<String> names, List<Datatype> flatListTypes) {
    1641        log.trace("extractCompoundInfo(): start: name={}", name);
    1642
    1643        if (isArray() || isVLEN()) {
    1644            log.trace("extractCompoundInfo(): top-level types is ARRAY or VLEN; extracting compound info from base type");
    1645            ((H5Datatype) getDatatypeBase()).extractCompoundInfo(name, names, flatListTypes);
    1646        }
    1647        else {
    1648            if (compoundMemberNames == null) {
    1649                log.debug("extractCompoundInfo(): compoundMemberNames is null");
    1650                log.trace("extractCompoundInfo(): finish");
    1651                return;
    1652            }
    1653
    1654            Datatype mtype = null;
    1655            String mname = null;
    1656
    1657            log.trace("extractCompoundInfo(): nMembers={}", compoundMemberNames.size());
    1658
    1659            if (compoundMemberNames.size() <= 0) {
    1660                log.debug("extractCompoundInfo(): datatype has no members");
    1661                log.trace("extractCompoundInfo(): finish");
    1662                return;
    1663            }
    1664
    1665            for (int i = 0; i < compoundMemberNames.size(); i++) {
    1666                log.trace("extractCompoundInfo(): nMembers[{}]", i);
    1667
    1668                mtype = compoundMemberTypes.get(i);
    1669                log.trace("extractCompoundInfo():[{}] mtype={} with size={}", i, mtype.getDescription(), mtype.getDatatypeSize());
    1670
    1671                if (names != null) {
    1672                    mname = name + compoundMemberNames.get(i);
    1673                    log.trace("extractCompoundInfo():[{}] mname={}, name={}", i, mname, name);
    1674                }
    1675
    1676                if (mtype.isCompound()) {
    1677                    ((H5Datatype) mtype).extractCompoundInfo(mname + CompoundDS.separator, names, flatListTypes);
    1678                    log.debug("extractCompoundInfo(): continue after recursive H5T_COMPOUND[{}]:", i);
    1679                    continue;
    1680                }
    1681
    1682                if (names != null) {
    1683                    names.add(mname);
    1684                }
    1685                flatListTypes.add(mtype);
    1686
    1687            } // for (int i=0; i<nMembers; i++)
    1688        }
    1689
    1690        log.trace("extractCompoundInfo(): finish");
    1691    } // extractCompoundInfo
    1692
    1693    /**
    1694     * Creates a datatype of a compound with one field.
    1695     * <p>
    1696     * This function is needed to read/write data field by field.
    1697     *
    1698     * @param member_name
    1699     *            The name of the datatype
    1700     *
    1701     * @return the identifier of the compound datatype.
    1702     *
    1703     * @throws HDF5Exception
    1704     *             If there is an error at the HDF5 library level.
    1705     */
    1706    public long createCompoundFieldType(String member_name) throws HDF5Exception {
    1707        log.trace("createCompoundFieldType(): start member_name={}", member_name);
    1708        long nested_tid = -1;
    1709        long tmp_tid1 = -1;
    1710        try {
    1711            log.trace("createCompoundFieldType(): {} Member is type {} of size={} with baseType={}", member_name, getDescription(), getDatatypeSize(), getDatatypeBase());
    1712            tmp_tid1 = createNative();
    1713
    1714            /*
    1715             * If this member is nested inside a compound, keep inserting
    1716             * it into a newly-created compound datatype until we reach
    1717             * the top-level compound type.
    1718             */
    1719            int sep = member_name.lastIndexOf(CompoundDS.separator);
    1720            while (sep > 0) {
    1721                String theName = member_name.substring(sep + 1);
    1722
    1723                log.trace("createCompoundFieldType(): member with name {} is nested inside compound", theName);
    1724
    1725                nested_tid = H5.H5Tcreate(HDF5Constants.H5T_COMPOUND, datatypeSize);
    1726                H5.H5Tinsert(nested_tid, theName, 0, tmp_tid1);
    1727                close(tmp_tid1);
    1728                tmp_tid1 = nested_tid;
    1729                member_name = member_name.substring(0, sep);
    1730                sep = member_name.lastIndexOf(CompoundDS.separator);
    1731            }
    1732
    1733            nested_tid = H5.H5Tcreate(HDF5Constants.H5T_COMPOUND, datatypeSize);
    1734
    1735            H5.H5Tinsert(nested_tid, member_name, 0, tmp_tid1);
    1736        }
    1737        finally {
    1738            close(tmp_tid1);
    1739        }
    1740
    1741        log.trace("createCompoundFieldType(): finish");
    1742        return nested_tid;
    1743    }
    1744}