    001/*****************************************************************************
    002 * Copyright by The HDF Group.                                               *
    003 * Copyright by the Board of Trustees of the University of Illinois.         *
    004 * All rights reserved.                                                      *
    005 *                                                                           *
    006 * This file is part of the HDF Java Products distribution.                  *
    007 * The full copyright notice, including terms governing use, modification,   *
    008 * and redistribution, is contained in the COPYING file, which can be found  *
    009 * at the root of the source code distribution tree,                         *
    010 * or in https://www.hdfgroup.org/licenses.                                  *
    011 * If you do not have access to either file, you may request a copy from     *
    012 * help@hdfgroup.org.                                                        *
    013 ****************************************************************************/
    014
    015package hdf.object;
    016
    017import java.util.ArrayList;
    018import java.util.HashMap;
    019import java.util.Iterator;
    020import java.util.List;
    021import java.util.Map;
    022import java.util.Map.Entry;
    023
    024import org.slf4j.Logger;
    025import org.slf4j.LoggerFactory;
    026
    027/**
    028 * Datatype is an abstract class that defines datatype characteristics and APIs for a data type.
    029 *
    030 * A datatype has four basic characteristics: class, size, byte order and sign. These characteristics are defined in the
    031 * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    032 *
    033 * These characteristics apply to all the sub-classes. The sub-classes may have different ways to describe a datatype.
    034 * We here define the <strong> native datatype</strong> to the datatype used by the sub-class. For example, H5Datatype
    035 * uses a datatype identifier (hid_t) to specify a datatype. NC2Datatype uses ucar.nc2.DataType object to describe its
    036 * datatype. "Native" here is different from the "native" definition in the HDF5 library.
    037 *
    038 * Two functions, createNative() and fromNative(), are defined to convert the general characteristics to/from the native
    039 * datatype. Sub-classes must implement these functions so that the conversion will be done correctly. The values of the
    040 * CLASS member are not identical to HDF5 values for a datatype class.
    041 *
    042 * @version 1.1 9/4/2007
    043 * @author Peter X. Cao
    044 */
    045public abstract class Datatype extends HObject implements MetaDataContainer
    046{
    047    private static final long serialVersionUID = -581324710549963177L;
    048
    049    private static final Logger log = LoggerFactory.getLogger(Datatype.class);
    050
    051    /**
    052     * The default definition for datatype size, order, and sign.
    053     */
    054    public static final int NATIVE = -1;
    055
    056    /**
    057     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    058     */
    059    public static final int CLASS_NO_CLASS = -1;
    060
    061    /**
    062     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    063     */
    064    public static final int CLASS_INTEGER = 0;
    065
    066    /**
    067     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    068     */
    069    public static final int CLASS_FLOAT = 1;
    070
    071    /**
    072     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    073     */
    074    public static final int CLASS_CHAR = 2;
    075
    076    /**
    077     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    078     */
    079    public static final int CLASS_STRING = 3;
    080
    081    /**
    082     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    083     */
    084    public static final int CLASS_BITFIELD = 4;
    085
    086    /**
    087     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    088     */
    089    public static final int CLASS_OPAQUE = 5;
    090
    091    /**
    092     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    093     */
    094    public static final int CLASS_COMPOUND = 6;
    095
    096    /**
    097     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    098     */
    099    public static final int CLASS_REFERENCE = 7;
    100
    101    /**
    102     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    103     */
    104    public static final int CLASS_ENUM = 8;
    105
    106    /**
    107     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    108     */
    109    public static final int CLASS_VLEN = 9;
    110
    111    /**
    112     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    113     */
    114    public static final int CLASS_ARRAY = 10;
    115
    116    /**
    117     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    118     */
    119    public static final int CLASS_TIME = 11;
    120
    121    /**
    122     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    123     */
    124    public static final int ORDER_LE = 0;
    125
    126    /**
    127     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    128     */
    129    public static final int ORDER_BE = 1;
    130
    131    /**
    132     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    133     */
    134    public static final int ORDER_VAX = 2;
    135
    136    /**
    137     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    138     */
    139    public static final int ORDER_NONE = 3;
    140
    141    /**
    142     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    143     */
    144    public static final int SIGN_NONE = 0;
    145
    146    /**
    147     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    148     */
    149    public static final int SIGN_2 = 1;
    150
    151    /**
    152     * See <a href="https://hdfgroup.github.io/hdf5/_h5_t__u_g.html#sec_datatype">HDF5 Datatypes in HDF5 User Guide</a>
    153     */
    154    public static final int NSGN = 2;
    155
    156    /**
    157     * The description of the datatype.
    158     */
    159    protected String datatypeDescription = null;
    160
    161    /**
    162     * The description of the datatype.
    163     */
    164    protected boolean datatypeNATIVE = false;
    165
    166    /**
    167     * The class of the datatype.
    168     */
    169    protected int datatypeClass;
    170
    171    /**
    172     * The size (in bytes) of the datatype.
    173     */
    174    protected long datatypeSize;
    175
    176    /**
    177     * The byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, and
    178     * ORDER_VAX.
    179     */
    180    protected int datatypeOrder;
    181
    182    /**
    183     * The sign of the datatype.
    184     */
    185    protected int datatypeSign;
    186
    187    /**
    188     * The base datatype of this datatype (null if this datatype is atomic).
    189     */
    190    protected Datatype baseType;
    191
    192    /**
    193     * Determines whether this datatype is a named datatype
    194     */
    195    protected boolean isNamed = false;
    196
    197    /**
    198     * The dimensions of the ARRAY element of an ARRAY datatype.
    199     */
    200    protected long[] arrayDims;
    201
    202    /**
    203     * Determines whether this datatype is a variable-length type.
    204     */
    205    protected boolean isVLEN = false;
    206
    207    /**
    208     * Determines whether this datatype is a variable-length string type.
    209     */
    210    protected boolean isVariableStr = false;
    211
    212    /**
    213     * The (name, value) pairs of enum members.
    214     */
    215    protected Map<String, String> enumMembers;
    216
    217    /**
    218     * The list of names of members of a compound Datatype.
    219     */
    220    protected List<String> compoundMemberNames;
    221
    222    /**
    223     * The list of types of members of a compound Datatype.
    224     */
    225    protected List<Datatype> compoundMemberTypes;
    226
    227    /**
    228     * The list of offsets of members of a compound Datatype.
    229     */
    230    protected List<Long> compoundMemberOffsets;
    231
    232    /**
    233     * Constructs a named datatype with a given file, name and path.
    234     *
    235     * @param theFile
    236     *            the HDF file.
    237     * @param typeName
    238     *            the name of the datatype, e.g "12-bit Integer".
    239     * @param typePath
    240     *            the full group path of the datatype, e.g. "/datatypes/".
    241     */
    242    public Datatype(FileFormat theFile, String typeName, String typePath) {
    243        this(theFile, typeName, typePath, null);
    244    }
    245
    246    /**
    247     * @deprecated Not for public use in the future.<br>
    248     *             Using {@link #Datatype(FileFormat, String, String)}
    249     *
    250     * @param theFile
    251     *            the HDF file.
    252     * @param typeName
    253     *            the name of the datatype, e.g "12-bit Integer".
    254     * @param typePath
    255     *            the full group path of the datatype, e.g. "/datatypes/".
    256     * @param oid
    257     *            the oidof the datatype.
    258     */
    259    @Deprecated
    260    public Datatype(FileFormat theFile, String typeName, String typePath, long[] oid) {
    261        super(theFile, typeName, typePath, oid);
    262    }
    263
    264    /**
    265     * Constructs a Datatype with specified class, size, byte order and sign.
    266     *
    267     * The following is a list of a few examples of Datatype.
    268     * <ol>
    269     * <li>to create unsigned native integer<br>
    270     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
    271     * <li>to create 16-bit signed integer with big endian<br>
    272     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
    273     * <li>to create native float<br>
    274     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
    275     * <li>to create 64-bit double<br>
    276     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
    277     * </ol>
    278     *
    279     * @param tclass
    280     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    281     * @param tsize
    282     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
    283     *            Valid values are NATIVE or a positive value.
    284     * @param torder
    285     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
    286     *            ORDER_NONE and NATIVE.
    287     * @param tsign
    288     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
    289     *
    290     * @throws Exception
    291     *            if there is an error
    292     */
    293    public Datatype(int tclass, int tsize, int torder, int tsign) throws Exception {
    294        this(tclass, tsize, torder, tsign, null);
    295    }
    296
    297    /**
    298     * Constructs a Datatype with specified class, size, byte order and sign.
    299     *
    300     * The following is a list of a few examples of Datatype.
    301     * <ol>
    302     * <li>to create unsigned native integer<br>
    303     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
    304     * <li>to create 16-bit signed integer with big endian<br>
    305     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
    306     * <li>to create native float<br>
    307     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
    308     * <li>to create 64-bit double<br>
    309     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
    310     * </ol>
    311     *
    312     * @param tclass
    313     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and
    314     *            etc.
    315     * @param tsize
    316     *            the size of the datatype in bytes, e.g. for a 32-bit integer,
    317     *            the size is 4.
    318     *            Valid values are NATIVE or a positive value.
    319     * @param torder
    320     *            the byte order of the datatype. Valid values are ORDER_LE,
    321     *            ORDER_BE, ORDER_VAX, ORDER_NONE and NATIVE.
    322     * @param tsign
    323     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
    324     * @param tbase
    325     *            the base datatype of the new datatype
    326     *
    327     * @throws Exception
    328     *            if there is an error
    329     */
    330    public Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) throws Exception {
    331        this(null, tclass, tsize, torder, tsign, tbase, null);
    332    }
    333
    334    /**
    335     * Constructs a Datatype with specified class, size, byte order and sign.
    336     *
    337     * The following is a list of a few examples of Datatype.
    338     * <ol>
    339     * <li>to create unsigned native integer<br>
    340     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
    341     * <li>to create 16-bit signed integer with big endian<br>
    342     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
    343     * <li>to create native float<br>
    344     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
    345     * <li>to create 64-bit double<br>
    346     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
    347     * </ol>
    348     *
    349     * @param theFile
    350     *            the HDF file.
    351     * @param tclass
    352     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    353     * @param tsize
    354     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
    355     *            Valid values are NATIVE or a positive value.
    356     * @param torder
    357     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
    358     *            ORDER_NONE and NATIVE.
    359     * @param tsign
    360     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
    361     * @param tbase
    362     *            the base datatype of the new datatype
    363     * @param pbase
    364     *            the parent datatype of the new datatype
    365     *
    366     * @throws Exception
    367     *            if there is an error
    368     */
    369    public Datatype(FileFormat theFile, int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase) throws Exception {
    370        super(theFile, null, null, null);
    371        if ((tsize == 0) || (tsize < 0 && tsize != Datatype.NATIVE))
    372            throw new Exception("invalid datatype size - " + tsize);
    373        if ((torder != Datatype.ORDER_LE) && (torder != Datatype.ORDER_BE) && (torder != Datatype.ORDER_VAX)
    374                && (torder != Datatype.ORDER_NONE) && (torder != Datatype.NATIVE))
    375            throw new Exception("invalid datatype order - " + torder);
    376        if ((tsign != Datatype.SIGN_NONE) && (tsign != Datatype.SIGN_2) && (tsign != Datatype.NATIVE))
    377            throw new Exception("invalid datatype sign - " + tsign);
    378
    379        datatypeClass = tclass;
    380        datatypeSize = tsize;
    381        if (datatypeSize == NATIVE)
    382            datatypeNATIVE = true;
    383        else
    384            datatypeNATIVE = false;
    385        datatypeOrder = torder;
    386        datatypeSign = tsign;
    387        enumMembers = null;
    388        baseType = tbase;
    389        arrayDims = null;
    390        isVariableStr = (datatypeClass == Datatype.CLASS_STRING) && (tsize < 0);
    391        isVLEN = (datatypeClass == Datatype.CLASS_VLEN) || isVariableStr;
    392
    393        compoundMemberNames = new ArrayList<>();
    394        compoundMemberTypes = new ArrayList<>();
    395        compoundMemberOffsets = new ArrayList<>();
    396
    397        log.trace("datatypeClass={} datatypeSize={} datatypeOrder={} datatypeSign={} baseType={}",
    398                datatypeClass, datatypeSize, datatypeOrder, datatypeSign, baseType);
    399    }
    400
    401    /**
    402     * Constructs a Datatype with specified class, size, byte order and sign.
    403     *
    404     * The following is a list of a few examples of Datatype.
    405     * <ol>
    406     * <li>to create unsigned native integer<br>
    407     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
    408     * <li>to create 16-bit signed integer with big endian<br>
    409     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
    410     * <li>to create native float<br>
    411     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
    412     * <li>to create 64-bit double<br>
    413     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
    414     * </ol>
    415     *
    416     * @param tclass
    417     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    418     * @param tsize
    419     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
    420     *            Valid values are NATIVE or a positive value.
    421     * @param torder
    422     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
    423     *            ORDER_NONE and NATIVE.
    424     * @param tsign
    425     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
    426     * @param tbase
    427     *            the base datatype of the new datatype
    428     * @param pbase
    429     *            the parent datatype of the new datatype
    430     *
    431     * @throws Exception
    432     *            if there is an error
    433     */
    434    public Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase) throws Exception {
    435        this(null, tclass, tsize, torder, tsign, tbase, pbase);
    436    }
    437
    438    /**
    439     * Constructs a Datatype with a given native datatype identifier.
    440     *
    441     * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5,
    442     *
    443     * <pre>
    444     * long tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
    445     * Datatype dtype = new Datatype(tid);
    446     * </pre>
    447     *
    448     * will construct a datatype equivalent to new Datatype(CLASS_INTEGER, 4, NATIVE, SIGN_NONE);
    449     *
    450     * @see #fromNative(long tid)
    451     * @param theFile
    452     *            the HDF file.
    453     * @param tid
    454     *            the native datatype identifier.
    455     *
    456     * @throws Exception
    457     *            if there is an error
    458     */
    459    public Datatype(FileFormat theFile, long tid) throws Exception {
    460        this(theFile, tid, null);
    461    }
    462
    463    /**
    464     * Constructs a Datatype with a given native datatype identifier.
    465     *
    466     * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5,
    467     *
    468     * <pre>
    469     * long tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
    470     * Datatype dtype = new Datatype(tid);
    471     * </pre>
    472     *
    473     * will construct a datatype equivalent to new Datatype(CLASS_INTEGER, 4, NATIVE, SIGN_NONE);
    474     *
    475     * @see #fromNative(long tid)
    476     * @param theFile
    477     *            the HDF file.
    478     * @param tid
    479     *            the native datatype identifier.
    480     * @param pbase
    481     *            the parent datatype of the new datatype
    482     *
    483     * @throws Exception
    484     *            if there is an error
    485     */
    486    public Datatype(FileFormat theFile, long tid, Datatype pbase) throws Exception {
    487        this(theFile, CLASS_NO_CLASS, NATIVE, NATIVE, NATIVE, null, pbase);
    488    }
    489
    490    /**
    491     * Opens access to this named datatype. Sub-classes must replace this default implementation. For
    492     * example, in H5Datatype, open() function H5.H5Topen(loc_id, name) to get the datatype identifier.
    493     *
    494     * @return the datatype identifier if successful; otherwise returns negative value.
    495     */
    496    @Override
    497    public long open() {
    498        return -1;
    499    }
    500
    501    /**
    502     * Closes a datatype identifier.
    503     *
    504     * Sub-classes must replace this default implementation.
    505     *
    506     * @param id
    507     *            the datatype identifier to close.
    508     */
    509    @Override
    510    public abstract void close(long id);
    511
    512    /**
    513     * Returns the class of the datatype. Valid values are:
    514     * <ul>
    515     * <li>CLASS_NO_CLASS
    516     * <li>CLASS_INTEGER
    517     * <li>CLASS_FLOAT
    518     * <li>CLASS_CHAR
    519     * <li>CLASS_STRING
    520     * <li>CLASS_BITFIELD
    521     * <li>CLASS_OPAQUE
    522     * <li>CLASS_COMPOUND
    523     * <li>CLASS_REFERENCE
    524     * <li>CLASS_ENUM
    525     * <li>CLASS_VLEN
    526     * <li>CLASS_ARRAY
    527     * </ul>
    528     *
    529     * @return the class of the datatype.
    530     */
    531    public int getDatatypeClass() {
    532        return datatypeClass;
    533    }
    534
    535    /**
    536     * Returns the size of the datatype in bytes. For example, for a 32-bit
    537     * integer, the size is 4 (bytes).
    538     *
    539     * @return the size of the datatype.
    540     */
    541    public long getDatatypeSize() {
    542        return datatypeSize;
    543    }
    544
    545    /**
    546     * Returns the byte order of the datatype. Valid values are
    547     * <ul>
    548     * <li>ORDER_LE
    549     * <li>ORDER_BE
    550     * <li>ORDER_VAX
    551     * <li>ORDER_NONE
    552     * </ul>
    553     *
    554     * @return the byte order of the datatype.
    555     */
    556    public int getDatatypeOrder() {
    557        return datatypeOrder;
    558    }
    559
    560    /**
    561     * Returns the sign (SIGN_NONE, SIGN_2) of an integer datatype.
    562     *
    563     * @return the sign of the datatype.
    564     */
    565    public int getDatatypeSign() {
    566        return datatypeSign;
    567    }
    568
    569    /**
    570     * Returns the base datatype for this datatype.
    571     *
    572     * For example, in a dataset of type ARRAY of integer, the datatype of the dataset is ARRAY. The
    573     * datatype of the base type is integer.
    574     *
    575     * @return the datatype of the contained basetype.
    576     */
    577    public Datatype getDatatypeBase() {
    578        return baseType;
    579    }
    580
    581    /**
    582     * Sets the (key, value) pairs of enum members for enum datatype.
    583     *
    584     * For Example,
    585     * <dl>
    586     * <dt>setEnumMembers("-40=lowTemp, 90=highTemp")</dt>
    587     * <dd>sets the key of enum member lowTemp to -40 and highTemp to 90.</dd>
    588     * <dt>setEnumMembers("lowTemp, highTemp")</dt>
    589     * <dd>sets enum members to defaults, i.e. 0=lowTemp and 1=highTemp</dd>
    590     * <dt>setEnumMembers("10=lowTemp, highTemp")</dt>
    591     * <dd>sets enum member lowTemp to 10 and highTemp to 11.</dd>
    592     * </dl>
    593     *
    594     * @param enumStr
    595     *            the (key, value) pairs of enum members
    596     */
    597    public final void setEnumMembers(String enumStr) {
    598        log.trace("setEnumMembers: start enum_members={}", enumStr);
    599        if (enumStr != null) {
    600            enumMembers = new HashMap<>();
    601            String[] entries = enumStr.split(",");
    602            for (String entry : entries) {
    603                String[] keyValue = entry.split("=");
    604                enumMembers.put(keyValue[0].trim(), keyValue[1].trim());
    605                if (log.isTraceEnabled())
    606                    log.trace("setEnumMembers: value={} name={}", keyValue[0].trim(), keyValue[1].trim());
    607            }
    608        }
    609        datatypeDescription = null; //reset description
    610        log.trace("setEnumMembers: finish enum size={}", enumMembers.size());
    611    }
    612
    613    /**
    614     * Returns the Map&lt;String,String&gt; pairs of enum members for enum datatype.
    615     *
    616     * @return enumStr Map&lt;String,String%gt; pairs of enum members
    617     */
    618    public final Map<String, String> getEnumMembers() {
    619        if (enumMembers == null) {
    620            log.trace("getEnumMembers: null");
    621            enumMembers = new HashMap<>();
    622        }
    623
    624        return enumMembers;
    625    }
    626
    627    /**
    628     * Returns the HashMap pairs of enum members for enum datatype.
    629     *
    630     * For Example,
    631     * <dl>
    632     * <dt>getEnumMembersAsString()</dt>
    633     * <dd>returns "10=lowTemp, 40=highTemp"</dd>
    634     * </dl>
    635     *
    636     * @return enumStr the (key, value) pairs of enum members
    637     */
    638    @SuppressWarnings("rawtypes")
    639    public final String getEnumMembersAsString() {
    640        StringBuilder enumStr = new StringBuilder();
    641        if (getEnumMembers() != null) {
    642            Iterator<Entry<String, String>> entries = enumMembers.entrySet().iterator();
    643            int i = enumMembers.size();
    644            log.trace("getEnumMembersAsString: enum size={}", i);
    645            while (entries.hasNext()) {
    646                Entry thisEntry = entries.next();
    647                enumStr.append((String) thisEntry.getKey())
    648                       .append("=")
    649                       .append((String) thisEntry.getValue());
    650
    651                i--;
    652                if (i > 0)
    653                    enumStr.append(", ");
    654            }
    655        }
    656        log.trace("getEnumMembersAsString: finish {}", enumStr);
    657        return enumStr.toString();
    658    }
    659
    660    /**
    661     * Returns the dimensions of an Array Datatype.
    662     *
    663     * @return dims the dimensions of the Array Datatype
    664     */
    665    public final long[] getArrayDims() {
    666        return arrayDims;
    667    }
    668
    669
    670    /**
    671     * Returns the member names of a Compound Datatype.
    672     *
    673     * @return member names of a Compound Datatype
    674     */
    675    public final List<String> getCompoundMemberNames() {
    676        return compoundMemberNames;
    677    }
    678
    679
    680    /**
    681     * Returns member types of a Compound Datatype.
    682     *
    683     * @return member types of a Compound Datatype
    684     */
    685    public final List<Datatype> getCompoundMemberTypes() {
    686        return compoundMemberTypes;
    687    }
    688
    689
    690    /**
    691     * Returns the member offsets of a Compound Datatype.
    692     *
    693     * @return member offsets of a Compound Datatype
    694     */
    695    public final List<Long> getCompoundMemberOffsets() {
    696        return compoundMemberOffsets;
    697    }
    698
    699    /**
    700     * Converts the datatype object to a native datatype.
    701     *
    702     * Subclasses must implement it so that this datatype will be converted accordingly. Use close() to
    703     * close the native identifier; otherwise, the datatype will be left open.
    704     *
    705     * For example, a HDF5 datatype created from<br>
    706     *
    707     * <pre>
    708     * H5Dataype dtype = new H5Datatype(CLASS_INTEGER, 4, NATIVE, SIGN_NONE);
    709     * int tid = dtype.createNative();
    710     * </pre>
    711     *
    712     * The "tid" will be the HDF5 datatype id of a 64-bit unsigned integer, which is equivalent to
    713     *
    714     * <pre>
    715     * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
    716     * </pre>
    717     *
    718     * @return the identifier of the native datatype.
    719     */
    720    public abstract long createNative();
    721
    722    /**
    723     * Set datatype characteristics (class, size, byte order and sign) from a given datatype identifier.
    724     *
    725     * Sub-classes must implement it so that this datatype will be converted accordingly.
    726     *
    727     * For example, if the type identifier is a 64-bit unsigned integer created from HDF5,
    728     *
    729     * <pre>
    730     * H5Datatype dtype = new H5Datatype();
    731     * dtype.fromNative(HDF5Constants.H5T_NATIVE_UNINT32);
    732     * </pre>
    733     *
    734     * Where dtype is equivalent to <br>
    735     * new H5Datatype(CLASS_INTEGER, 4, NATIVE, SIGN_NONE);
    736     *
    737     * @param nativeID
    738     *            the datatype identifier.
    739     */
    740    public abstract void fromNative(long nativeID);
    741
    742    /**
    743     * If the datatype is a reference, then return the type.
    744     *
    745     * @return the datatype reference type if successful; otherwise returns negative value.
    746     */
    747    public long getReferenceType() {
    748        return -1;
    749    }
    750
    751    /**
    752     * Returns a short text description of this datatype.
    753     *
    754     * @return a short text description of this datatype
    755     */
    756    public String getDescription() {
    757        if (datatypeDescription != null)
    758            return datatypeDescription;
    759
    760        StringBuilder description = new StringBuilder();
    761
    762        switch (datatypeClass) {
    763        case CLASS_CHAR:
    764            description.append("8-bit ").append((isUnsigned() ? "unsigned " : "")).append("integer");
    765            break;
    766        case CLASS_INTEGER:
    767            log.trace("getDescription(): Int [{}]", datatypeNATIVE);
    768            if (datatypeNATIVE)
    769                description.append("native ").append((isUnsigned() ? "unsigned " : "")).append("integer");
    770            else
    771                description.append(String.valueOf(datatypeSize * 8)).append("-bit ")
    772                .append((isUnsigned() ? "unsigned " : "")).append("integer");
    773            break;
    774        case CLASS_FLOAT:
    775            if (datatypeNATIVE)
    776                description.append("native floating-point");
    777            else
    778                description.append(String.valueOf(datatypeSize * 8)).append("-bit floating-point");
    779            break;
    780        case CLASS_STRING:
    781            description.append("String");
    782            break;
    783        case CLASS_REFERENCE:
    784            description.append("Object reference");
    785            break;
    786        case CLASS_OPAQUE:
    787            if (datatypeNATIVE)
    788                description.append("native opaque");
    789            else
    790                description.append(String.valueOf(datatypeSize * 8)).append("-bit opaque");
    791            break;
    792        case CLASS_BITFIELD:
    793            if (datatypeNATIVE)
    794                description.append("native bitfield");
    795            else
    796                description.append(String.valueOf(datatypeSize * 8)).append("-bit bitfield");
    797            break;
    798        case CLASS_ENUM:
    799            if (datatypeNATIVE)
    800                description.append("native enum");
    801            else
    802                description.append(String.valueOf(datatypeSize * 8)).append("-bit enum");
    803            break;
    804        case CLASS_ARRAY:
    805            description.append("Array");
    806
    807            if (arrayDims != null) {
    808                description.append(" [");
    809                for (int i = 0; i < arrayDims.length; i++) {
    810                    description.append(arrayDims[i]);
    811                    if (i < arrayDims.length - 1)
    812                        description.append(" x ");
    813                }
    814                description.append("]");
    815            }
    816
    817            break;
    818        case CLASS_COMPOUND:
    819            description.append("Compound");
    820            break;
    821        case CLASS_VLEN:
    822            description.append("Variable-length");
    823            break;
    824        default:
    825            description.append("Unknown");
    826            break;
    827        }
    828
    829        if (baseType != null)
    830            description.append(" of " + baseType.getDescription());
    831
    832        return description.toString();
    833    }
    834
    835    /**
    836     * Checks if this datatype is unsigned.
    837     *
    838     * @return true if the datatype is unsigned;
    839     *         otherwise, returns false.
    840     */
    841    public boolean isUnsigned() {
    842        if (baseType != null)
    843            return baseType.isUnsigned();
    844        else {
    845            if (isCompound()) {
    846                if ((compoundMemberTypes != null) && !compoundMemberTypes.isEmpty()) {
    847                    boolean allMembersUnsigned = true;
    848
    849                    Iterator<Datatype> cmpdTypeListIT = compoundMemberTypes.iterator();
    850                    while (cmpdTypeListIT.hasNext()) {
    851                        Datatype next = cmpdTypeListIT.next();
    852
    853                        allMembersUnsigned = allMembersUnsigned && next.isUnsigned();
    854                    }
    855
    856                    return allMembersUnsigned;
    857                }
    858                else {
    859                    log.debug("isUnsigned(): compoundMemberTypes is null");
    860                    return false;
    861                }
    862            }
    863            else {
    864                return (datatypeSign == Datatype.SIGN_NONE);
    865            }
    866        }
    867    }
    868
    869    /**
    870     * Checks if this datatype is a boolean type.
    871     *
    872     * @return true if the datatype is boolean; false otherwise
    873     */
    874    public abstract boolean isText();
    875
    876    /**
    877     * Checks if this datatype is an integer type.
    878     *
    879     * @return true if the datatype is integer; false otherwise
    880     */
    881    public boolean isInteger() {
    882        return (datatypeClass == Datatype.CLASS_INTEGER);
    883    }
    884
    885    /**
    886     * Checks if this datatype is a floating-point type.
    887     *
    888     * @return true if the datatype is floating-point; false otherwise
    889     */
    890    public boolean isFloat() {
    891        return (datatypeClass == Datatype.CLASS_FLOAT);
    892    }
    893
    894    /**
    895     * Checks if this datatype is a named type.
    896     *
    897     * @return true if the datatype is named; false otherwise
    898     */
    899    public boolean isNamed() {
    900        return isNamed;
    901    }
    902
    903    /**
    904     * Checks if this datatype is a variable-length string type.
    905     *
    906     * @return true if the datatype is variable-length string; false otherwise
    907     */
    908    public boolean isVarStr() {
    909        return isVariableStr;
    910    }
    911
    912    /**
    913     * Checks if this datatype is a variable-length type.
    914     *
    915     * @return true if the datatype is variable-length; false otherwise
    916     */
    917    public boolean isVLEN() {
    918        return isVLEN;
    919    }
    920
    921    /**
    922     * Checks if this datatype is an compound type.
    923     *
    924     * @return true if the datatype is compound; false otherwise
    925     */
    926    public boolean isCompound() {
    927        return (datatypeClass == Datatype.CLASS_COMPOUND);
    928    }
    929
    930    /**
    931     * Checks if this datatype is an array type.
    932     *
    933     * @return true if the datatype is array; false otherwise
    934     */
    935    public boolean isArray() {
    936        return (datatypeClass == Datatype.CLASS_ARRAY);
    937    }
    938
    939    /**
    940     * Checks if this datatype is a string type.
    941     *
    942     * @return true if the datatype is string; false otherwise
    943     */
    944    public boolean isString() {
    945        return (datatypeClass == Datatype.CLASS_STRING);
    946    }
    947
    948    /**
    949     * Checks if this datatype is a character type.
    950     *
    951     * @return true if the datatype is character; false otherwise
    952     */
    953    public boolean isChar() {
    954        return (datatypeClass == Datatype.CLASS_CHAR);
    955    }
    956
    957    /**
    958     * Checks if this datatype is a reference type.
    959     *
    960     * @return true if the datatype is reference; false otherwise
    961     */
    962    public boolean isRef() {
    963        return (datatypeClass == Datatype.CLASS_REFERENCE);
    964    }
    965
    966    /**
    967     * Checks if this datatype is a enum type.
    968     *
    969     * @return true if the datatype is enum; false otherwise
    970     */
    971    public boolean isEnum() {
    972        return (datatypeClass == Datatype.CLASS_ENUM);
    973    }
    974
    975    /**
    976     * Checks if this datatype is a opaque type.
    977     *
    978     * @return true if the datatype is opaque; false otherwise
    979     */
    980    public boolean isOpaque() {
    981        return (datatypeClass == Datatype.CLASS_OPAQUE);
    982    }
    983
    984    /**
    985     * Checks if this datatype is a bitfield type.
    986     *
    987     * @return true if the datatype is bitfield; false otherwise
    988     */
    989    public boolean isBitField() {
    990        return (datatypeClass == Datatype.CLASS_BITFIELD);
    991    }
    992
    993    /* Implement interface MetaDataContainer */
    994
    995    /**
    996     * Removes all of the elements from metadata list.
    997     * The list should be empty after this call returns.
    998     */
    999    @Override
    1000    public void clear() {
    1001    }
    1002
    1003    /**
    1004     * Retrieves the object's metadata, such as attributes, from the file.
    1005     *
    1006     * Metadata, such as attributes, is stored in a List.
    1007     *
    1008     * @return the list of metadata objects.
    1009     *
    1010     * @throws Exception
    1011     *             if the metadata can not be retrieved
    1012     */
    1013    @Override
    1014    @SuppressWarnings("rawtypes")
    1015    public List getMetadata() throws Exception {
    1016        return null;
    1017    }
    1018
    1019    /**
    1020     * Writes a specific piece of metadata (such as an attribute) into the file.
    1021     *
    1022     * If an HDF(4&amp;5) attribute exists in the file, this method updates its
    1023     * value. If the attribute does not exist in the file, it creates the
    1024     * attribute in the file and attaches it to the object. It will fail to
    1025     * write a new attribute to the object where an attribute with the same name
    1026     * already exists. To update the value of an existing attribute in the file,
    1027     * one needs to get the instance of the attribute by getMetadata(), change
    1028     * its values, then use writeMetadata() to write the value.
    1029     *
    1030     * @param info
    1031     *            the metadata to write.
    1032     *
    1033     * @throws Exception
    1034     *             if the metadata can not be written
    1035     */
    1036    @Override
    1037    public void writeMetadata(Object info) throws Exception {
    1038        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement Datatype:writeMetadata.");
    1039    }
    1040
    1041    /**
    1042     * Deletes an existing piece of metadata from this object.
    1043     *
    1044     * @param info
    1045     *            the metadata to delete.
    1046     *
    1047     * @throws Exception
    1048     *             if the metadata can not be removed
    1049     */
    1050    @Override
    1051    public void removeMetadata(Object info) throws Exception {
    1052        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement Datatype:removeMetadata.");
    1053    }
    1054
    1055    /**
    1056     * Updates an existing piece of metadata attached to this object.
    1057     *
    1058     * @param info
    1059     *            the metadata to update.
    1060     *
    1061     * @throws Exception
    1062     *             if the metadata can not be updated
    1063     */
    1064    @Override
    1065    public void updateMetadata(Object info) throws Exception {
    1066        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement Datatype:updateMetadata.");
    1067    }
    1068
    1069    @Override
    1070    public String toString() {
    1071        return getDescription();
    1072    }
    1073}