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