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     * Returns a short text description of this datatype.
707     *
708     * @return a short text description of this datatype
709     */
710    public String getDescription() {
711
712        if (datatypeDescription != null) {
713            return datatypeDescription;
714        }
715
716        StringBuilder description = new StringBuilder();
717
718        switch (datatypeClass) {
719            case CLASS_CHAR:
720                description.append("8-bit ").append((isUnsigned() ? "unsigned " : "")).append("integer");
721                break;
722            case CLASS_INTEGER:
723                if (datatypeSize == NATIVE)
724                    description.append("native ").append((isUnsigned() ? "unsigned " : "")).append("integer");
725                else
726                    description.append(String.valueOf(datatypeSize * 8)).append("-bit ")
727                            .append((isUnsigned() ? "unsigned " : "")).append("integer");
728                break;
729            case CLASS_FLOAT:
730                if (datatypeSize == NATIVE)
731                    description.append("native floating-point");
732                else
733                    description.append(String.valueOf(datatypeSize * 8)).append("-bit floating-point");
734                break;
735            case CLASS_STRING:
736                description.append("String");
737                break;
738            case CLASS_REFERENCE:
739                description.append("Object reference");
740                break;
741            case CLASS_OPAQUE:
742                if (datatypeSize == NATIVE)
743                    description.append("native opaque");
744                else
745                    description.append(String.valueOf(datatypeSize * 8)).append("-bit opaque");
746                break;
747            case CLASS_BITFIELD:
748                if (datatypeSize == NATIVE)
749                    description.append("native bitfield");
750                else
751                    description.append(String.valueOf(datatypeSize * 8)).append("-bit bitfield");
752                break;
753            case CLASS_ENUM:
754                if (datatypeSize == NATIVE)
755                    description.append("native enum");
756                else
757                    description.append(String.valueOf(datatypeSize * 8)).append("-bit enum");
758                break;
759            case CLASS_ARRAY:
760                description.append("Array");
761
762                if (arrayDims != null) {
763                    description.append(" [");
764                    for (int i = 0; i < arrayDims.length; i++) {
765                        description.append(arrayDims[i]);
766                        if (i < arrayDims.length - 1)
767                            description.append(" x ");
768                    }
769                    description.append("]");
770                }
771
772                break;
773            case CLASS_COMPOUND:
774                description.append("Compound");
775                break;
776            case CLASS_VLEN:
777                description.append("Variable-length");
778                break;
779            default:
780                description.append("Unknown");
781                break;
782        }
783
784        if (baseType != null) {
785            description.append(" of " + baseType.getDescription());
786        }
787
788        return description.toString();
789    }
790
791    /**
792     * Checks if this datatype is unsigned.
793     *
794     * @return true if the datatype is unsigned;
795     *         otherwise, returns false.
796     */
797    public boolean isUnsigned() {
798        if (baseType != null)
799            return baseType.isUnsigned();
800        else {
801            if (isCompound()) {
802                if ((compoundMemberTypes != null) && !compoundMemberTypes.isEmpty()) {
803                    boolean allMembersUnsigned = true;
804
805                    Iterator<Datatype> cmpdTypeListIT = compoundMemberTypes.iterator();
806                    while (cmpdTypeListIT.hasNext()) {
807                        Datatype next = cmpdTypeListIT.next();
808
809                        allMembersUnsigned = allMembersUnsigned && next.isUnsigned();
810                    }
811
812                    return allMembersUnsigned;
813                }
814                else {
815                    log.debug("isUnsigned(): compoundMemberTypes is null");
816                    return false;
817                }
818            }
819            else {
820                return (datatypeSign == Datatype.SIGN_NONE);
821            }
822        }
823    }
824
825    public abstract boolean isText();
826
827    /**
828     * Checks if this datatype is an integer type.
829     *
830     * @return true if the datatype is integer; false otherwise
831     */
832    public boolean isInteger() {
833        return (datatypeClass == Datatype.CLASS_INTEGER);
834    }
835
836    /**
837     * Checks if this datatype is a floating-point type.
838     *
839     * @return true if the datatype is floating-point; false otherwise
840     */
841    public boolean isFloat() {
842        return (datatypeClass == Datatype.CLASS_FLOAT);
843    }
844
845    /**
846     * Checks if this datatype is a named type.
847     *
848     * @return true if the datatype is named; false otherwise
849     */
850    public boolean isNamed() {
851        return isNamed;
852    }
853
854    /**
855     * Checks if this datatype is a variable-length string type.
856     *
857     * @return true if the datatype is variable-length string; false otherwise
858     */
859    public boolean isVarStr() {
860        return isVariableStr;
861    }
862
863    /**
864     * Checks if this datatype is a variable-length type.
865     *
866     * @return true if the datatype is variable-length; false otherwise
867     */
868    public boolean isVLEN() {
869        return isVLEN;
870    }
871
872    /**
873     * Checks if this datatype is an compound type.
874     *
875     * @return true if the datatype is compound; false otherwise
876     */
877    public boolean isCompound() {
878        return (datatypeClass == Datatype.CLASS_COMPOUND);
879    }
880
881    /**
882     * Checks if this datatype is an array type.
883     *
884     * @return true if the datatype is array; false otherwise
885     */
886    public boolean isArray() {
887        return (datatypeClass == Datatype.CLASS_ARRAY);
888    }
889
890    /**
891     * Checks if this datatype is a string type.
892     *
893     * @return true if the datatype is string; false otherwise
894     */
895    public boolean isString() {
896        return (datatypeClass == Datatype.CLASS_STRING);
897    }
898
899    /**
900     * Checks if this datatype is a character type.
901     *
902     * @return true if the datatype is character; false otherwise
903     */
904    public boolean isChar() {
905        return (datatypeClass == Datatype.CLASS_CHAR);
906    }
907
908    /**
909     * Checks if this datatype is a reference type.
910     *
911     * @return true if the datatype is reference; false otherwise
912     */
913    public boolean isRef() {
914        return (datatypeClass == Datatype.CLASS_REFERENCE);
915    }
916
917    /**
918     * Checks if this datatype is a enum type.
919     *
920     * @return true if the datatype is enum; false otherwise
921     */
922    public boolean isEnum() {
923        return (datatypeClass == Datatype.CLASS_ENUM);
924    }
925
926    /**
927     * Checks if this datatype is a opaque type.
928     *
929     * @return true if the datatype is opaque; false otherwise
930     */
931    public boolean isOpaque() {
932        return (datatypeClass == Datatype.CLASS_OPAQUE);
933    }
934
935    /**
936     * Checks if this datatype is a bitfield type.
937     *
938     * @return true if the datatype is bitfield; false otherwise
939     */
940    public boolean isBitField() {
941        return (datatypeClass == Datatype.CLASS_BITFIELD);
942    }
943
944    /*
945     * (non-Javadoc)
946     *
947     * @see hdf.object.DataFormat#getMetadata()
948     */
949    @Override
950    @SuppressWarnings("rawtypes")
951    public List getMetadata() throws Exception {
952        return null;
953    }
954
955    /*
956     * (non-Javadoc)
957     *
958     * @see hdf.object.DataFormat#writeMetadata(java.lang.Object)
959     */
960    @Override
961    public void writeMetadata(Object info) throws Exception {
962        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement Datatype:writeMetadata.");
963    }
964
965    /*
966     * (non-Javadoc)
967     *
968     * @see hdf.object.DataFormat#removeMetadata(java.lang.Object)
969     */
970    @Override
971    public void removeMetadata(Object info) throws Exception {
972        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement Datatype:removeMetadata.");
973    }
974
975    /*
976     * (non-Javadoc)
977     *
978     * @see hdf.object.DataFormat#updateMetadata(java.lang.Object)
979     */
980    @Override
981    public void updateMetadata(Object info) throws Exception {
982        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement Datatype:updateMetadata.");
983    }
984
985    @Override
986    public String toString() {
987        return getDescription();
988    }
989}