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     * The dimensions of the ARRAY element of an ARRAY datatype.
187     */
188    protected long[] arrayDims;
189
190    /**
191     * Determines whether this datatype is a variable-length type.
192     */
193    protected boolean isVLEN = false;
194    protected boolean isVariableStr = false;
195
196    /**
197     * The (name, value) pairs of enum members.
198     */
199    protected Map<String, String> enumMembers;
200
201    /**
202     * The list of names of members of a compound Datatype.
203     */
204    protected List<String> compoundMemberNames;
205
206    /**
207     * The list of types of members of a compound Datatype.
208     */
209    protected List<Datatype> compoundMemberTypes;
210
211    /**
212     * The list of offsets of members of a compound Datatype.
213     */
214    protected List<Long> compoundMemberOffsets;
215
216    /**
217     * Constructs a named datatype with a given file, name and path.
218     *
219     * @param theFile
220     *            the HDF file.
221     * @param typeName
222     *            the name of the datatype, e.g "12-bit Integer".
223     * @param typePath
224     *            the full group path of the datatype, e.g. "/datatypes/".
225     */
226    public Datatype(FileFormat theFile, String typeName, String typePath) {
227        this(theFile, typeName, typePath, null);
228    }
229
230    /**
231     * @deprecated Not for public use in the future.<br>
232     *             Using {@link #Datatype(FileFormat, String, String)}
233     *
234     * @param theFile
235     *            the HDF file.
236     * @param typeName
237     *            the name of the datatype, e.g "12-bit Integer".
238     * @param typePath
239     *            the full group path of the datatype, e.g. "/datatypes/".
240     * @param oid
241     *            the oidof the datatype.
242     */
243    @Deprecated
244    public Datatype(FileFormat theFile, String typeName, String typePath, long[] oid) {
245        super(theFile, typeName, typePath, oid);
246    }
247
248    /**
249     * Constructs a Datatype with specified class, size, byte order and sign.
250     * <p>
251     * The following is a list of a few examples of Datatype.
252     * <ol>
253     * <li>to create unsigned native integer<br>
254     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
255     * <li>to create 16-bit signed integer with big endian<br>
256     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
257     * <li>to create native float<br>
258     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
259     * <li>to create 64-bit double<br>
260     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
261     * </ol>
262     *
263     * @param tclass
264     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
265     * @param tsize
266     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
267     *            Valid values are NATIVE or a positive value.
268     * @param torder
269     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
270     *            ORDER_NONE and NATIVE.
271     * @param tsign
272     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
273     *
274     * @throws Exception
275     *            if there is an error
276     */
277    public Datatype(int tclass, int tsize, int torder, int tsign) throws Exception {
278        this(tclass, tsize, torder, tsign, null);
279    }
280
281    /**
282     * Constructs a Datatype with specified class, size, byte order and sign.
283     * <p>
284     * The following is a list of a few examples of Datatype.
285     * <ol>
286     * <li>to create unsigned native integer<br>
287     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
288     * <li>to create 16-bit signed integer with big endian<br>
289     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
290     * <li>to create native float<br>
291     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
292     * <li>to create 64-bit double<br>
293     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
294     * </ol>
295     *
296     * @param tclass
297     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and
298     *            etc.
299     * @param tsize
300     *            the size of the datatype in bytes, e.g. for a 32-bit integer,
301     *            the size is 4.
302     *            Valid values are NATIVE or a positive value.
303     * @param torder
304     *            the byte order of the datatype. Valid values are ORDER_LE,
305     *            ORDER_BE, ORDER_VAX, ORDER_NONE and NATIVE.
306     * @param tsign
307     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
308     * @param tbase
309     *            the base datatype of the new datatype
310     *
311* @throws Exception
312     *            if there is an error
313     */
314    public Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) throws Exception {
315        this(tclass, tsize, torder, tsign, tbase, null);
316    }
317
318    /**
319     * Constructs a Datatype with specified class, size, byte order and sign.
320     * <p>
321     * The following is a list of a few examples of Datatype.
322     * <ol>
323     * <li>to create unsigned native integer<br>
324     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
325     * <li>to create 16-bit signed integer with big endian<br>
326     * Datatype type = new Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
327     * <li>to create native float<br>
328     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
329     * <li>to create 64-bit double<br>
330     * Datatype type = new Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
331     * </ol>
332     *
333     * @param tclass
334     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
335     * @param tsize
336     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
337     *            Valid values are NATIVE or a positive value.
338     * @param torder
339     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
340     *            ORDER_NONE and NATIVE.
341     * @param tsign
342     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
343     * @param tbase
344     *            the base datatype of the new datatype
345     * @param pbase
346     *            the parent datatype of the new datatype
347     *
348* @throws Exception
349     *            if there is an error
350     */
351    public Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase) throws Exception {
352        if ((tsize == 0) || (tsize < 0 && tsize != NATIVE))
353            throw new Exception("invalid datatype size - " + tsize);
354        if ((torder != ORDER_LE) && (torder != ORDER_BE) && (torder != ORDER_VAX)
355                && (torder != ORDER_NONE) && (torder != NATIVE))
356            throw new Exception("invalid datatype order - " + torder);
357        if ((tsign != SIGN_NONE) && (tsign != SIGN_2) && (tsign != NATIVE))
358            throw new Exception("invalid datatype sign - " + tsign);
359
360        datatypeClass = tclass;
361        datatypeSize = tsize;
362        datatypeOrder = torder;
363        datatypeSign = tsign;
364        enumMembers = null;
365        baseType = tbase;
366        arrayDims = null;
367        isVariableStr = (datatypeClass == Datatype.CLASS_STRING) && (tsize < 0);
368        isVLEN = (datatypeClass == Datatype.CLASS_VLEN) || isVariableStr;
369
370        compoundMemberNames = new ArrayList<>();
371        compoundMemberTypes = new ArrayList<>();
372        compoundMemberOffsets = new ArrayList<>();
373
374        log.trace("datatypeClass={} datatypeSize={} datatypeOrder={} datatypeSign={} baseType={}",
375                datatypeClass, datatypeSize, datatypeOrder, datatypeSign, baseType);
376    }
377
378    /**
379     * Constructs a Datatype with a given native datatype identifier.
380     * <p>
381     * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5,
382     *
383     * <pre>
384     * long tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
385     * Datatype dtype = new Datatype(tid);
386     * </pre>
387     *
388     * will construct a datatype equivalent to new Datatype(CLASS_INTEGER, 4, NATIVE, SIGN_NONE);
389     *
390     * @see #fromNative(long tid)
391     * @param tid
392     *            the native datatype identifier.
393     *
394* @throws Exception
395     *            if there is an error
396     */
397    public Datatype(long tid) throws Exception {
398        this(tid, null);
399    }
400
401    /**
402     * Constructs a Datatype with a given native datatype identifier.
403     * <p>
404     * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5,
405     *
406     * <pre>
407     * long tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
408     * Datatype dtype = new Datatype(tid);
409     * </pre>
410     *
411     * will construct a datatype equivalent to new Datatype(CLASS_INTEGER, 4, NATIVE, SIGN_NONE);
412     *
413     * @see #fromNative(long tid)
414     * @param tid
415     *            the native datatype identifier.
416     * @param pbase
417     *            the parent datatype of the new datatype
418     *
419* @throws Exception
420     *            if there is an error
421     */
422    public Datatype(long tid, Datatype pbase) throws Exception {
423        this(CLASS_NO_CLASS, NATIVE, NATIVE, NATIVE, null, pbase);
424    }
425
426    /**
427     * Opens access to this named datatype. Sub-classes must replace this default implementation. For
428     * example, in H5Datatype, open() function H5.H5Topen(loc_id, name) to get the datatype identifier.
429     *
430     * @return the datatype identifier if successful; otherwise returns negative value.
431     */
432    @Override
433    public long open() {
434        return -1;
435    }
436
437    /**
438     * Closes a datatype identifier.
439     * <p>
440     * Sub-classes must replace this default implementation.
441     *
442     * @param id
443     *            the datatype identifier to close.
444     */
445    @Override
446    public abstract void close(long id);
447
448    /**
449     * Returns the class of the datatype. Valid values are:
450     * <ul>
451     * <li>CLASS_NO_CLASS
452     * <li>CLASS_INTEGER
453     * <li>CLASS_FLOAT
454     * <li>CLASS_CHAR
455     * <li>CLASS_STRING
456     * <li>CLASS_BITFIELD
457     * <li>CLASS_OPAQUE
458     * <li>CLASS_COMPOUND
459     * <li>CLASS_REFERENCE
460     * <li>CLASS_ENUM
461     * <li>CLASS_VLEN
462     * <li>CLASS_ARRAY
463     * </ul>
464     *
465     * @return the class of the datatype.
466     */
467    public int getDatatypeClass() {
468        return datatypeClass;
469    }
470
471    /**
472     * Returns the size of the datatype in bytes. For example, for a 32-bit
473     * integer, the size is 4 (bytes).
474     *
475     * @return the size of the datatype.
476     */
477    public long getDatatypeSize() {
478        return datatypeSize;
479    }
480
481    /**
482     * Returns the byte order of the datatype. Valid values are
483     * <ul>
484     * <li>ORDER_LE
485     * <li>ORDER_BE
486     * <li>ORDER_VAX
487     * <li>ORDER_NONE
488     * </ul>
489     *
490     * @return the byte order of the datatype.
491     */
492    public int getDatatypeOrder() {
493        return datatypeOrder;
494    }
495
496    /**
497     * Returns the sign (SIGN_NONE, SIGN_2) of an integer datatype.
498     *
499     * @return the sign of the datatype.
500     */
501    public int getDatatypeSign() {
502        return datatypeSign;
503    }
504
505    /**
506     * Returns the base datatype for this datatype.
507     * <p>
508     * For example, in a dataset of type ARRAY of integer, the datatype of the dataset is ARRAY. The
509     * datatype of the base type is integer.
510     *
511     * @return the datatype of the contained basetype.
512     */
513    public Datatype getDatatypeBase() {
514        return baseType;
515    }
516
517    /**
518     * Sets the (key, value) pairs of enum members for enum datatype.
519     * <p>
520     * For Example,
521     * <dl>
522     * <dt>setEnumMembers("-40=lowTemp, 90=highTemp")</dt>
523     * <dd>sets the key of enum member lowTemp to -40 and highTemp to 90.</dd>
524     * <dt>setEnumMembers("lowTemp, highTemp")</dt>
525     * <dd>sets enum members to defaults, i.e. 0=lowTemp and 1=highTemp</dd>
526     * <dt>setEnumMembers("10=lowTemp, highTemp")</dt>
527     * <dd>sets enum member lowTemp to 10 and highTemp to 11.</dd>
528     * </dl>
529     *
530     * @param enumStr
531     *            the (key, value) pairs of enum members
532     */
533    public final void setEnumMembers(String enumStr) {
534        log.trace("setEnumMembers: is_enum enum_members={}", enumStr);
535        enumMembers = new HashMap<>();
536        String[] entries = enumStr.split(",");
537        for (String entry : entries) {
538            String[] keyValue = entry.split("=");
539            enumMembers.put(keyValue[0].trim(), keyValue[1].trim());
540            if (log.isTraceEnabled())
541                log.trace("setEnumMembers: is_enum value={} name={}", keyValue[0].trim(), keyValue[1].trim());
542        }
543    }
544
545    /**
546     * Returns the Map&lt;String,String&gt; pairs of enum members for enum datatype.
547     *
548     * @return enumStr Map&lt;String,String%gt; pairs of enum members
549     */
550    public final Map<String, String> getEnumMembers() {
551        if (enumMembers == null) {
552            enumMembers = new HashMap<>();
553            enumMembers.put("1", "0");
554            enumMembers.put("2", "1");
555        }
556
557        return enumMembers;
558    }
559
560    /**
561     * Returns the HashMap pairs of enum members for enum datatype.
562     * <p>
563     * For Example,
564     * <dl>
565     * <dt>getEnumMembersAsString()</dt>
566     * <dd>returns "10=lowTemp, 40=highTemp"</dd>
567     * </dl>
568     *
569     * @return enumStr the (key, value) pairs of enum members
570     */
571    @SuppressWarnings("rawtypes")
572    public final String getEnumMembersAsString() {
573        if (enumMembers == null) {
574            enumMembers = new HashMap<>();
575            enumMembers.put("1", "0");
576            enumMembers.put("2", "1");
577        }
578
579        StringBuilder enumStr = new StringBuilder();
580        Iterator<Entry<String, String>> entries = enumMembers.entrySet().iterator();
581        int i = enumMembers.size();
582        while (entries.hasNext()) {
583            Entry thisEntry = entries.next();
584            enumStr.append((String) thisEntry.getKey())
585                   .append("=")
586                   .append((String) thisEntry.getValue());
587
588            i--;
589            if (i > 0)
590                enumStr.append(", ");
591        }
592        return enumStr.toString();
593    }
594
595    /**
596     * Returns the dimensions of an Array Datatype.
597     *
598     * @return dims the dimensions of the Array Datatype
599     */
600    public final long[] getArrayDims() {
601        return arrayDims;
602    }
603
604    public final List<String> getCompoundMemberNames() {
605        return compoundMemberNames;
606    }
607
608    public final List<Datatype> getCompoundMemberTypes() {
609        return compoundMemberTypes;
610    }
611
612    /**
613     * Converts the datatype object to a native datatype.
614     *
615     * Subclasses must implement it so that this datatype will be converted accordingly. Use close() to
616     * close the native identifier; otherwise, the datatype will be left open.
617     * <p>
618     * For example, a HDF5 datatype created from<br>
619     *
620     * <pre>
621     * H5Dataype dtype = new H5Datatype(CLASS_INTEGER, 4, NATIVE, SIGN_NONE);
622     * int tid = dtype.createNative();
623     * </pre>
624     *
625     * The "tid" will be the HDF5 datatype id of a 64-bit unsigned integer, which is equivalent to
626     *
627     * <pre>
628     * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
629     * </pre>
630     *
631     * @return the identifier of the native datatype.
632     */
633    public abstract long createNative();
634
635    /**
636     * Set datatype characteristics (class, size, byte order and sign) from a given datatype identifier.
637     * <p>
638     * Sub-classes must implement it so that this datatype will be converted accordingly.
639     * <p>
640     * For example, if the type identifier is a 64-bit unsigned integer created from HDF5,
641     *
642     * <pre>
643     * H5Datatype dtype = new H5Datatype();
644     * dtype.fromNative(HDF5Constants.H5T_NATIVE_UNINT32);
645     * </pre>
646     *
647     * Where dtype is equivalent to <br>
648     * new H5Datatype(CLASS_INTEGER, 4, NATIVE, SIGN_NONE);
649     *
650     * @param nativeID
651     *            the datatype identifier.
652     */
653    public abstract void fromNative(long nativeID);
654
655    /**
656     * Returns a short text description of this datatype.
657     *
658     * @return a short text description of this datatype
659     */
660    public String getDescription() {
661        log.trace("getDescription(): start");
662
663        if (datatypeDescription != null) {
664            log.trace("getDescription(): finish");
665            return datatypeDescription;
666        }
667
668        StringBuilder description = new StringBuilder();
669
670        switch (datatypeClass) {
671            case CLASS_CHAR:
672                description.append("8-bit ").append((isUnsigned() ? "unsigned " : "")).append("integer");
673                break;
674            case CLASS_INTEGER:
675                if (datatypeSize == NATIVE)
676                    description.append("native ").append((isUnsigned() ? "unsigned " : "")).append("integer");
677                else
678                    description.append(String.valueOf(datatypeSize * 8)).append("-bit ")
679                            .append((isUnsigned() ? "unsigned " : "")).append("integer");
680                break;
681            case CLASS_FLOAT:
682                if (datatypeSize == NATIVE)
683                    description.append("native floating-point");
684                else
685                    description.append(String.valueOf(datatypeSize * 8)).append("-bit floating-point");
686                break;
687            case CLASS_STRING:
688                description.append("String");
689                break;
690            case CLASS_REFERENCE:
691                description.append("Object reference");
692                break;
693            case CLASS_OPAQUE:
694                if (datatypeSize == NATIVE)
695                    description.append("native opaque");
696                else
697                    description.append(String.valueOf(datatypeSize * 8)).append("-bit opaque");
698                break;
699            case CLASS_BITFIELD:
700                if (datatypeSize == NATIVE)
701                    description.append("native bitfield");
702                else
703                    description.append(String.valueOf(datatypeSize * 8)).append("-bit bitfield");
704                break;
705            case CLASS_ENUM:
706                if (datatypeSize == NATIVE)
707                    description.append("native enum");
708                else
709                    description.append(String.valueOf(datatypeSize * 8)).append("-bit enum");
710                break;
711            case CLASS_ARRAY:
712                description.append("Array");
713
714                if (arrayDims != null) {
715                    description.append(" [");
716                    for (int i = 0; i < arrayDims.length; i++) {
717                        description.append(arrayDims[i]);
718                        if (i < arrayDims.length - 1)
719                            description.append(" x ");
720                    }
721                    description.append("]");
722                }
723
724                break;
725            case CLASS_COMPOUND:
726                description.append("Compound");
727                break;
728            case CLASS_VLEN:
729                description.append("Variable-length");
730                break;
731            default:
732                description.append("Unknown");
733                break;
734        }
735
736        if (baseType != null) {
737            description.append(" of " + baseType.getDescription());
738        }
739
740        log.trace("getDescription(): finish");
741        return description.toString();
742    }
743
744    /**
745     * Checks if this datatype is unsigned.
746     *
747     * @return true if the datatype is unsigned;
748     *         otherwise, returns false.
749     */
750    public boolean isUnsigned() {
751        if (baseType != null)
752            return baseType.isUnsigned();
753        else {
754            if (isCompound()) {
755                if ((compoundMemberTypes != null) && !compoundMemberTypes.isEmpty()) {
756                    boolean allMembersUnsigned = true;
757
758                    Iterator<Datatype> cmpdTypeListIT = compoundMemberTypes.iterator();
759                    while (cmpdTypeListIT.hasNext()) {
760                        Datatype next = cmpdTypeListIT.next();
761
762                        allMembersUnsigned = allMembersUnsigned && next.isUnsigned();
763                    }
764
765                    return allMembersUnsigned;
766                }
767                else {
768                    log.debug("isUnsigned(): compoundMemberTypes is null");
769                    return false;
770                }
771            }
772            else {
773                return (datatypeSign == Datatype.SIGN_NONE);
774            }
775        }
776    }
777
778    public abstract boolean isText();
779
780    /**
781     * Checks if this datatype is an integer type.
782     *
783     * @return true if the datatype is integer; false otherwise
784     */
785    public boolean isInteger() {
786        return (datatypeClass == Datatype.CLASS_INTEGER);
787    }
788
789    /**
790     * Checks if this datatype is a floating-point type.
791     *
792     * @return true if the datatype is floating-point; false otherwise
793     */
794    public boolean isFloat() {
795        return (datatypeClass == Datatype.CLASS_FLOAT);
796    }
797
798    /**
799     * Checks if this datatype is a variable-length string type.
800     *
801     * @return true if the datatype is variable-length string; false otherwise
802     */
803    public boolean isVarStr() {
804        return isVariableStr;
805    }
806
807    /**
808     * Checks if this datatype is a variable-length type.
809     *
810     * @return true if the datatype is variable-length; false otherwise
811     */
812    public boolean isVLEN() {
813        return isVLEN;
814    }
815
816    /**
817     * Checks if this datatype is an compound type.
818     *
819     * @return true if the datatype is compound; false otherwise
820     */
821    public boolean isCompound() {
822        return (datatypeClass == Datatype.CLASS_COMPOUND);
823    }
824
825    /**
826     * Checks if this datatype is an array type.
827     *
828     * @return true if the datatype is array; false otherwise
829     */
830    public boolean isArray() {
831        return (datatypeClass == Datatype.CLASS_ARRAY);
832    }
833
834    /**
835     * Checks if this datatype is a string type.
836     *
837     * @return true if the datatype is string; false otherwise
838     */
839    public boolean isString() {
840        return (datatypeClass == Datatype.CLASS_STRING);
841    }
842
843    /**
844     * Checks if this datatype is a character type.
845     *
846     * @return true if the datatype is character; false otherwise
847     */
848    public boolean isChar() {
849        return (datatypeClass == Datatype.CLASS_CHAR);
850    }
851
852    /**
853     * Checks if this datatype is a reference type.
854     *
855     * @return true if the datatype is reference; false otherwise
856     */
857    public boolean isRef() {
858        return (datatypeClass == Datatype.CLASS_REFERENCE);
859    }
860
861    /**
862     * Checks if this datatype is a enum type.
863     *
864     * @return true if the datatype is enum; false otherwise
865     */
866    public boolean isEnum() {
867        return (datatypeClass == Datatype.CLASS_ENUM);
868    }
869
870    /**
871     * Checks if this datatype is a opaque type.
872     *
873     * @return true if the datatype is opaque; false otherwise
874     */
875    public boolean isOpaque() {
876        return (datatypeClass == Datatype.CLASS_OPAQUE);
877    }
878
879    /**
880     * Checks if this datatype is a bitfield type.
881     *
882     * @return true if the datatype is bitfield; false otherwise
883     */
884    public boolean isBitField() {
885        return (datatypeClass == Datatype.CLASS_BITFIELD);
886    }
887
888    /*
889     * (non-Javadoc)
890     *
891     * @see hdf.object.DataFormat#getMetadata()
892     */
893    @Override
894    @SuppressWarnings("rawtypes")
895    public List getMetadata() throws Exception {
896        return null;
897    }
898
899    /*
900     * (non-Javadoc)
901     *
902     * @see hdf.object.DataFormat#writeMetadata(java.lang.Object)
903     */
904    @Override
905    public void writeMetadata(Object info) throws Exception {
906        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement Datatype:writeMetadata.");
907    }
908
909    /*
910     * (non-Javadoc)
911     *
912     * @see hdf.object.DataFormat#removeMetadata(java.lang.Object)
913     */
914    @Override
915    public void removeMetadata(Object info) throws Exception {
916        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement Datatype:removeMetadata.");
917    }
918
919    /*
920     * (non-Javadoc)
921     *
922     * @see hdf.object.DataFormat#updateMetadata(java.lang.Object)
923     */
924    @Override
925    public void updateMetadata(Object info) throws Exception {
926        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement Datatype:updateMetadata.");
927    }
928
929    @Override
930    public String toString() {
931        return getDescription();
932    }
933}