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