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