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