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 file COPYING.                     *
009 * COPYING can be found at the root of the source code distribution tree.    *
010 * If you do not have access to this file, you may request a copy from       *
011 * help@hdfgroup.org.                                                        *
012 ****************************************************************************/
013
014package hdf.object.h5;
015
016import java.lang.reflect.Array;
017import java.util.List;
018import java.util.StringTokenizer;
019import java.util.Vector;
020
021import hdf.hdf5lib.H5;
022import hdf.hdf5lib.HDF5Constants;
023import hdf.hdf5lib.HDFNativeData;
024import hdf.hdf5lib.exceptions.HDF5Exception;
025import hdf.hdf5lib.exceptions.HDF5LibraryException;
026import hdf.hdf5lib.structs.H5O_info_t;
027import hdf.object.Attribute;
028import hdf.object.Datatype;
029import hdf.object.FileFormat;
030
031/**
032 * This class defines HDF5 datatype characteristics and APIs for a data type.
033 * <p>
034 * This class provides several methods to convert an HDF5 datatype identifier to a datatype object, and vice versa. A
035 * datatype object is described by four basic fields: datatype class, size, byte order, and sign, while an HDF5 datatype
036 * is presented by a datatype identifier.
037 *
038 * @version 1.1 9/4/2007
039 * @author Peter X. Cao
040 */
041public class H5Datatype extends Datatype {
042    private static final long serialVersionUID = -750546422258749792L;
043
044    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(H5Datatype.class);
045
046    /**
047     * The list of attributes of this data object.
048     */
049    private List<Attribute> attributeList;
050
051    /** Flag to indicate if this datatype is a named datatype */
052    private boolean isNamed = false;
053
054    private int nAttributes = -1;
055
056    private H5O_info_t obj_info;
057
058    private boolean isVLEN = false;
059
060    private String description = null;
061
062    /**
063     * Constructs an named HDF5 data type object for a given file, dataset name and group path.
064     * <p>
065     * The datatype object represents an existing named datatype in file. For example, new H5Datatype(file, "dtype1",
066     * "/g0") constructs a datatype object that corresponds to the dataset,"dset1", at group "/g0".
067     *
068     * @param theFile
069     *            the file that contains the dataset.
070     * @param name
071     *            the name of the dataset such as "dset1".
072     * @param path
073     *            the group path to the dataset such as "/g0/".
074     */
075    public H5Datatype(FileFormat theFile, String name, String path) {
076        this(theFile, name, path, null);
077    }
078
079    /**
080     * @deprecated Not for public use in the future. <br>
081     *             Using {@link #H5Datatype(FileFormat, String, String)}
082     *
083     * @param theFile
084     *            the file that contains the dataset.
085     * @param name
086     *            the name of the dataset such as "dset1".
087     * @param path
088     *            the group path to the dataset such as "/g0/".
089     * @param oid
090     *            the oid of the dataset.
091     */
092    @Deprecated
093    public H5Datatype(FileFormat theFile, String name, String path, long[] oid) {
094        super(theFile, name, path, oid);
095        obj_info = new H5O_info_t(-1L, -1L, 0, 0, -1L, 0L, 0L, 0L, 0L, null, null, null);
096
097        if ((oid == null) && (theFile != null)) {
098            // retrieve the object ID
099            try {
100                byte[] ref_buf = H5.H5Rcreate(theFile.getFID(), this.getFullName(), HDF5Constants.H5R_OBJECT, -1);
101                this.oid = new long[1];
102                this.oid[0] = HDFNativeData.byteToLong(ref_buf, 0);
103            }
104            catch (Exception ex) {
105                log.debug("constructor ID {} for {} failed H5Rcreate", theFile.getFID(), this.getFullName());
106            }
107        }
108    }
109
110    /**
111     * Constructs a Datatype with specified class, size, byte order and sign.
112     * <p>
113     * The following is a list of a few example of H5Datatype.
114     * <ol>
115     * <li>to create unsigned native integer<br>
116     * H5Datatype type = new H5Dataype(CLASS_INTEGER, NATIVE, NATIVE, SIGN_NONE);
117     * <li>to create 16-bit signed integer with big endian<br>
118     * H5Datatype type = new H5Dataype(CLASS_INTEGER, 2, ORDER_BE, NATIVE);
119     * <li>to create native float<br>
120     * H5Datatype type = new H5Dataype(CLASS_FLOAT, NATIVE, NATIVE, -1);
121     * <li>to create 64-bit double<br>
122     * H5Datatype type = new H5Dataype(CLASS_FLOAT, 8, NATIVE, -1);
123     * </ol>
124     *
125     * @param tclass
126     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
127     * @param tsize
128     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
129     * @param torder
130     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX and ORDER_NONE
131     * @param tsign
132     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and MSGN
133     */
134    public H5Datatype(int tclass, int tsize, int torder, int tsign) {
135        super(tclass, tsize, torder, tsign);
136    }
137
138    /**
139     * Constructs a Datatype with specified class, size, byte order and sign.
140     * <p>
141     * The following is a list of a few example of H5Datatype.
142     * <ol>
143     * <li>to create unsigned native integer<br>
144     * H5Datatype type = new H5Dataype(CLASS_INTEGER, NATIVE, NATIVE, SIGN_NONE);
145     * <li>to create 16-bit signed integer with big endian<br>
146     * H5Datatype type = new H5Dataype(CLASS_INTEGER, 2, ORDER_BE, NATIVE);
147     * <li>to create native float<br>
148     * H5Datatype type = new H5Dataype(CLASS_FLOAT, NATIVE, NATIVE, -1);
149     * <li>to create 64-bit double<br>
150     * H5Datatype type = new H5Dataype(CLASS_FLOAT, 8, NATIVE, -1);
151     * </ol>
152     *
153     * @param tclass
154     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
155     * @param tsize
156     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
157     * @param torder
158     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX and ORDER_NONE
159     * @param tsign
160     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and MSGN
161     * @param tbase
162     *            the base datatype of the new datatype
163     */
164    public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) {
165        super(tclass, tsize, torder, tsign, tbase);
166    }
167
168    /**
169     * Constructs a Datatype with a given native datatype identifier.
170     * <p>
171     * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5,
172     *
173     * <pre>
174     * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
175     * Datatype dtype = new Datatype(tid);
176     * </pre>
177     *
178     * will construct a datatype equivalent to new Datatype(CLASS_INTEGER, 4, NATIVE, SIGN_NONE);
179     *
180     * @see #fromNative(int nativeID)
181     *
182     * @param nativeID
183     *            the native datatype identifier.
184     */
185    public H5Datatype(int nativeID) {
186        super(nativeID);
187
188        description = getDatatypeDescription(nativeID);
189        log.trace("H5Datatype(int nativeID) description={}", description);
190        fromNative(nativeID);
191    }
192
193    /*
194     * (non-Javadoc)
195     *
196     * @see hdf.object.DataFormat#hasAttribute()
197     */
198    public boolean hasAttribute() {
199        obj_info.num_attrs = nAttributes;
200
201        if (obj_info.num_attrs < 0) {
202            int tid = -1;
203            try {
204                tid = H5.H5Topen(getFID(), getPath() + getName(), HDF5Constants.H5P_DEFAULT);
205                fromNative(tid);
206                obj_info = H5.H5Oget_info(tid);
207                isNamed = true;
208            }
209            catch (Exception ex) {
210                obj_info.num_attrs = 0;
211            }
212            finally {
213                try {
214                    H5.H5Tclose(tid);
215                }
216                catch (Exception ex) {
217                    log.debug("hasAttribute(): H5Tclose(tid {}) failure:", tid, ex);
218                }
219            }
220        }
221
222        log.trace("hasAttribute(): nAttributes={}", obj_info.num_attrs);
223
224        return (obj_info.num_attrs > 0);
225    }
226
227    /**
228     * Converts values in an Enumeration Datatype to names.
229     * <p>
230     * This method searches the identified enumeration datatype for the values appearing in <code>inValues</code> and
231     * returns the names corresponding to those values. If a given value is not found in the enumeration datatype, the
232     * name corresponding to that value will be set to <code>null</code> in the string array that is returned.
233     * <p>
234     * If the method fails in general, null will be returned instead of a String array. An empty <code>inValues</code>
235     * parameter, an <code>outNames</code> array with a different number of entries than the <code>inValues</code>
236     * array, or an invalid <code>tid</code> would all cause general failure.
237     *
238     * @param tid
239     *            The identifier of the enumeration datatype.
240     * @param inValues
241     *            The array of enumerations values to be converted.
242     * @param outNames
243     *            The array of names to be populated. If null, the array will be created. If <code>outNames</code> is
244     *            not null, the number of entries must be the same as the number of values in <code>inValues</code>.
245     *
246     * @return The string array of names if successful; otherwise return null.
247     *
248     * @throws HDF5Exception
249     *             If there is an error at the HDF5 library level.
250     *
251     */
252    public static final String[] convertEnumValueToName(int tid, Object inValues, String[] outNames)
253            throws HDF5Exception {
254        log.trace("convertEnumValueToName start");
255        int inSize = 0;
256
257        String cName = inValues.getClass().getName();
258        boolean isArray = cName.lastIndexOf("[") >= 0;
259        if (isArray) {
260            inSize = Array.getLength(inValues);
261        }
262        else {
263            inSize = 1;
264        }
265
266        if ((inValues == null) || (inSize <= 0)
267                || ((outNames != null) && (inSize != Array.getLength(outNames)))) {
268            log.debug("convertEnumValueToName() failure: in/out values null or inSize not equal to outNames length");
269            log.debug("convertEnumValueToName(): inValues={} inSize={} outNames length={}", inValues, inSize, outNames.length);
270            log.trace("convertEnumValueToName(): finish");
271            return null;
272        }
273
274        int nMembers = H5.H5Tget_nmembers(tid);
275        if (nMembers <= 0) {
276            log.debug("convertEnumValueToName(): no members");
277            log.trace("convertEnumValueToName(): finish");
278            return null;
279        }
280
281        log.trace("convertEnumValueToName(): inSize={} nMembers={}", inSize, nMembers);
282        if (outNames == null) {
283            outNames = new String[inSize];
284        }
285        else {
286            // set values in existing array to null in case no match found
287            for (int i = 0; i < inSize; i++) {
288                outNames[i] = null;
289            }
290        }
291
292        String[] names = new String[nMembers];
293        int[] values = new int[nMembers];
294        int[] theValue = { 0 };
295
296        // Loop through the enumeration datatype and extract the names and
297        // values.
298        for (int i = 0; i < nMembers; i++) {
299            names[i] = H5.H5Tget_member_name(tid, i);
300            H5.H5Tget_member_value(tid, i, theValue);
301            values[i] = theValue[0];
302            log.trace("convertEnumValueToName(): extract member[{}] names[i]={} values[i]={}", i, names[i], values[i]);
303        }
304
305        int val = -1;
306
307        // Look for matches
308        for (int i = 0; i < inSize; i++) {
309            if (isArray) {
310                val = (Integer) Array.get(inValues, i);
311            }
312            else {
313                val = (Integer) inValues;
314            }
315            boolean notfound = true;
316            for (int j = 0; j < nMembers; j++) {
317                if (val == values[j]) {
318                    outNames[i] = names[j];
319                    notfound = false;
320                    break;
321                }
322            }
323            if(notfound) {
324                log.debug("convertEnumValueToName(): default name");
325                outNames[i] = "**ENUM ERR "+String.valueOf(val)+"**";
326            }
327        }
328
329        log.trace("convertEnumValueToName(): finish");
330        return outNames;
331    }
332
333    /**
334     * Converts names in an Enumeration Datatype to values.
335     * <p>
336     * This method searches the identified enumeration datatype for the names appearing in <code>inValues</code> and
337     * returns the values corresponding to those names.
338     *
339     * @param tid
340     *            The identifier of the enumeration datatype.
341     * @param in
342     *            The array of enumerations names to be converted.
343     * @param out
344     *            The array of values to be populated.
345     *
346     * @return The int array of values if successful; otherwise return null.
347     *
348     * @throws HDF5Exception
349     *             If there is an error at the HDF5 library level.
350     *
351     */
352    public static final int[] convertEnumNameToValue(int tid, String[] in, int[] out) throws HDF5Exception {
353        log.trace("convertEnumNameToValue start");
354        int size = 0;
355
356        if ((in == null) || ((size = Array.getLength(in)) <= 0) || ((out != null) && (size != Array.getLength(out)))) {
357            log.debug("convertEnumNameToValue() failure: in/out values null or in size not equal to out size");
358            log.debug("convertEnumNameToValue(): in={} inSize={} out={} outSize={}", in.toString(), in.length, out.toString(), out.length);
359            log.trace("convertEnumValueToName(): finish");
360            return null;
361        }
362
363        int nMembers = H5.H5Tget_nmembers(tid);
364        if (nMembers <= 0) {
365            log.debug("convertEnumNameToValue(): no members");
366            log.trace("convertEnumNameToValue(): finish");
367            return null;
368        }
369
370        if (out == null) {
371            out = new int[size];
372        }
373        else {
374            // set values in existing array to -1 in case no match found
375            for (int i = 0; i < size; i++) {
376                out[i] = -1;
377            }
378        }
379
380        String[] names = new String[nMembers];
381        int[] values = new int[nMembers];
382        int[] theValue = { 0 };
383
384        // Loop through the enumeration datatype and extract the names and
385        // values.
386        for (int i = 0; i < nMembers; i++) {
387            names[i] = H5.H5Tget_member_name(tid, i);
388            H5.H5Tget_member_value(tid, i, theValue);
389            values[i] = theValue[0];
390        }
391
392        for (int i = 0; i < size; i++) {
393            if (in[i] == null || in[i].length() <= 0)
394                continue;
395
396            for (int j = 0; j < nMembers; j++) {
397                if (in[i].equalsIgnoreCase(names[j])) {
398                    out[i] = values[j];
399                    break;
400                }
401            }
402        }
403
404        log.trace("convertEnumNameToValue(): finish");
405        return out;
406    }
407
408    /*
409     * (non-Javadoc)
410     *
411     * @see hdf.object.Datatype#fromNative(int)
412     */
413    @Override
414    public void fromNative(int tid) {
415        log.trace("fromNative(): start: tid={}", tid);
416        int tclass = -1;
417        int tsize = -1;
418        int torder = -1;
419        boolean isChar = false, isUchar = false;
420
421        if (tid < 0) {
422            datatypeClass = CLASS_NO_CLASS;
423        }
424        else {
425            try {
426                tclass = H5.H5Tget_class(tid);
427                tsize = H5.H5Tget_size(tid);
428                torder = H5.H5Tget_order(tid);
429                isVLEN = (tclass == HDF5Constants.H5T_VLEN) || H5.H5Tis_variable_str(tid);
430                log.trace("fromNative(): tclass={}, tsize={}, torder={}, isVLEN={}", tclass, tsize, torder, isVLEN);
431            }
432            catch (Exception ex) {
433                log.debug("fromNative(): failure: ", ex);
434                datatypeClass = CLASS_NO_CLASS;
435            }
436
437            if (torder == HDF5Constants.H5T_ORDER_BE)
438                datatypeOrder = ORDER_BE;
439            else
440                datatypeOrder = ORDER_LE;
441
442            try {
443                isUchar = H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_UCHAR);
444                isChar = (H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_CHAR) || isUchar);
445            }
446            catch (Exception ex) {
447                log.debug("fromNative(): native char type failure: ", ex);
448            }
449
450            if (tclass == HDF5Constants.H5T_ARRAY) {
451                int tmptid = -1;
452                datatypeClass = CLASS_ARRAY;
453                try {
454                    int ndims = H5.H5Tget_array_ndims(tid);
455                    dims = new long[ndims];
456                    H5.H5Tget_array_dims(tid, dims);
457                    tmptid = H5.H5Tget_super(tid);
458                    baseType = new H5Datatype(tmptid);
459                    isVLEN = (baseType.getDatatypeClass() == HDF5Constants.H5T_VLEN) || H5.H5Tis_variable_str(tmptid);
460                    log.trace("fromNative:baseType={} tclass={}, isVLEN={}", tmptid, tclass, isVLEN);
461                }
462                catch (Exception ex) {
463                    log.debug("fromNative(): array type failure: ", ex);
464                }
465                finally {
466                    try {
467                        H5.H5Tclose(tmptid);
468                    }
469                    catch (Exception ex) {
470                        log.debug("fromNative(): array H5Tclose(tmptid {}) failure: ", tmptid, ex);
471                    }
472                }
473            }
474            else if (tclass == HDF5Constants.H5T_COMPOUND) {
475                datatypeClass = CLASS_COMPOUND;
476
477                try {
478                    int nMembers = H5.H5Tget_nmembers(tid);
479                    compoundMemberNames = new Vector<String>(nMembers);
480                    compoundMemberTypes = new Vector<Datatype>(nMembers);
481                    compoundMemberOffsets = new Vector<Long>(nMembers);
482                    compoundMemberFieldIDs = new Vector<Integer>(nMembers);
483
484                    for (int i = 0; i < nMembers; i++) {
485                        String memberName = H5.H5Tget_member_name(tid, i);
486                        long memberOffset = H5.H5Tget_member_offset(tid, i);
487                        int memberID = -1;
488                        H5Datatype t = null;
489                        try {
490                            memberID = H5.H5Tget_member_type(tid, i);
491                            t = new H5Datatype(memberID);
492                        }
493                        catch (Exception ex1) {
494                            log.debug("fromNative(): compound type failure: ", ex1);
495                        }
496                        finally {
497                            try {
498                                H5.H5Tclose(memberID);
499                            }
500                            catch (Exception ex2) {
501                                log.debug("fromNative(): compound H5Tclose(memberID {}) failure: ", memberID, ex2);
502                            }
503                        }
504
505                        compoundMemberNames.add(i, memberName);
506                        compoundMemberOffsets.add(i, memberOffset);
507                        compoundMemberFieldIDs.add(i, memberID);
508                        compoundMemberTypes.add(i, t);
509                    }
510                }
511                catch (HDF5LibraryException ex) {
512                    log.debug("fromNative(): compound type failure: ", ex);
513                }
514            }
515            else if (isChar) {
516                datatypeClass = CLASS_CHAR;
517                if (isUchar)
518                    datatypeSign = SIGN_NONE;
519                else
520                    datatypeSign = SIGN_2;
521            }
522            else if (tclass == HDF5Constants.H5T_INTEGER) {
523                datatypeClass = CLASS_INTEGER;
524                try {
525                    int tsign = H5.H5Tget_sign(tid);
526                    if (tsign == HDF5Constants.H5T_SGN_NONE) {
527                        datatypeSign = SIGN_NONE;
528                    }
529                    else
530                        datatypeSign = SIGN_2;
531
532                }
533                catch (Exception ex) {
534                    log.debug("fromNative(): int type failure: ", ex);
535                }
536            }
537            else if (tclass == HDF5Constants.H5T_FLOAT) {
538                datatypeClass = CLASS_FLOAT;
539            }
540            else if (tclass == HDF5Constants.H5T_STRING) {
541                try {
542                    isVLEN = H5.H5Tis_variable_str(tid);
543                }
544                catch (Exception ex) {
545                    log.debug("fromNative(): var str type failure: ", ex);
546                }
547
548                datatypeClass = CLASS_STRING;
549            }
550            else if (tclass == HDF5Constants.H5T_REFERENCE) {
551                datatypeClass = CLASS_REFERENCE;
552            }
553            else if (tclass == HDF5Constants.H5T_ENUM) {
554                datatypeClass = CLASS_ENUM;
555                try {
556                    int nMember = H5.H5Tget_nmembers(tid);
557                    String name = null;
558                    byte[] val = new byte[tsize];
559                    String enumStr = "";
560                    for (int i = 0; i < nMember; i++) {
561                        name = H5.H5Tget_member_name(tid, i);
562                        H5.H5Tget_member_value(tid, i, val);
563                        enumStr += name + "=";
564                        switch (H5.H5Tget_size(tid)) {
565                        case 1:
566                            enumStr += (HDFNativeData.byteToByte(val[0]))[0];
567                            break;
568                        case 2:
569                            enumStr += (HDFNativeData.byteToShort(val))[0];
570                            break;
571                        case 4:
572                            enumStr += (HDFNativeData.byteToInt(val))[0];
573                            break;
574                        case 8:
575                            enumStr += (HDFNativeData.byteToLong(val))[0];
576                            break;
577                        default:
578                            enumStr += "?";
579                            break;
580                        }
581                        if(i < nMember-1)
582                            enumStr += ",";
583                    }
584                    enumMembers = enumStr;
585                }
586                catch (Exception ex) {
587                    log.debug("fromNative(): enum type failure: ", ex);
588                }
589            }
590            else if (tclass == HDF5Constants.H5T_VLEN) {
591                int tmptid = -1;
592                datatypeClass = CLASS_VLEN;
593                try {
594                    tmptid = H5.H5Tget_super(tid);
595                    baseType = new H5Datatype(tmptid);
596                }
597                catch (Exception ex) {
598                }
599                finally {
600                    try {
601                        H5.H5Tclose(tmptid);
602                    }
603                    catch (Exception ex) {
604                        log.debug("fromNative(): vlen H5Tclose(tmptid {}) failure: ", tmptid, ex);
605                    }
606                }
607            }
608            else if (tclass == HDF5Constants.H5T_BITFIELD) {
609                datatypeClass = CLASS_BITFIELD;
610            }
611            else if (tclass == HDF5Constants.H5T_OPAQUE) {
612                datatypeClass = CLASS_OPAQUE;
613            }
614            else {
615                log.debug("fromNative(): datatypeClass is unknown");
616            }
617
618            if (isVLEN)
619                datatypeSize = -1;
620            else
621                datatypeSize = tsize;
622        }
623        log.trace("fromNative(): datatypeClass={} baseType={} datatypeSize={}", datatypeClass, baseType, datatypeSize);
624        log.trace("fromNative(): finish");
625    }
626
627    /**
628     * @deprecated Not for public use in the future.<br>
629     *             Using {@link hdf.hdf5lib.H5#H5Tget_native_type(int)}
630     *             <p>
631     *             Return the HDF5 memory datatype identifier based on the HDF5 datatype identifier on disk
632     *             <p>
633     * @param tid
634     *            the datatype identification disk.
635     *
636     * @return the memory datatype identifier if successful, and negative otherwise.
637     */
638    @Deprecated
639    public static int toNative(int tid) {
640        // data type information
641        int native_type = -1;
642
643        try {
644            native_type = H5.H5Tget_native_type(tid);
645        }
646        catch (Exception ex) {
647            log.debug("toNative(): H5Tget_native_type(tid {}) failure: ", tid, ex);
648        }
649
650        try {
651            if (H5.H5Tis_variable_str(tid))
652                H5.H5Tset_size(native_type, HDF5Constants.H5T_VARIABLE);
653        }
654        catch (Exception ex) {
655            log.debug("toNative(): var str type size failure: ", ex);
656        }
657
658        return native_type;
659    }
660
661    /*
662     * (non-Javadoc)
663     *
664     * @see hdf.object.Datatype#toNative()
665     */
666    @Override
667    public int toNative() {
668        log.trace("toNative(): start");
669
670        int tid = -1;
671        int tmptid = -1;
672
673        if (isNamed) {
674            try {
675                tid = H5.H5Topen(getFID(), getPath() + getName(), HDF5Constants.H5P_DEFAULT);
676            }
677            catch (Exception ex) {
678                log.debug("toNative(): name {} H5Topen failure: ", getPath() + getName(), ex);
679            }
680        }
681
682        if (tid >= 0) {
683            log.trace("toNative(): tid >= 0");
684            log.trace("toNative(): finish");
685            return tid;
686        }
687
688        // figure the datatype
689        try {
690            log.trace("toNative(): datatypeClass={} baseType={} datatypeSize={}", datatypeClass, baseType, datatypeSize);
691            switch (datatypeClass) {
692            case CLASS_ARRAY:
693                if (baseType != null) {
694                    if ((tmptid = baseType.toNative()) >= 0) {
695                        try {
696                            tid = H5.H5Tarray_create(tmptid, dims.length, dims);
697                        }
698                        finally {
699                            close(tmptid);
700                        }
701                    }
702                }
703                else {
704                    log.debug("toNative(): CLASS_ARRAY base type is NULL");
705                }
706                break;
707            case CLASS_COMPOUND:
708                try {
709                    tid = H5.H5Tcreate(CLASS_COMPOUND, datatypeSize);
710
711                    for (int i = 0; i < compoundMemberNames.size(); i++) {
712                        String memberName = compoundMemberNames.get(i);
713                        long memberOffset = compoundMemberOffsets.get(i);
714                        int memberID = compoundMemberFieldIDs.get(i);
715
716                        H5.H5Tinsert(tid, memberName, memberOffset, memberID);
717                    }
718                }
719                catch (Exception ex) {
720                    log.trace("toNative(): failure: ", ex);
721                }
722                break;
723            case CLASS_INTEGER:
724            case CLASS_ENUM:
725                if (datatypeSize == 1) {
726                    log.trace("toNative(): CLASS_INT-ENUM is H5T_NATIVE_INT8");
727                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8);
728                }
729                else if (datatypeSize == 2) {
730                    log.trace("toNative(): CLASS_INT-ENUM is H5T_NATIVE_INT16");
731                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT16);
732                }
733                else if (datatypeSize == 4) {
734                    log.trace("toNative(): CLASS_INT-ENUM is H5T_NATIVE_INT32");
735                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32);
736                }
737                else if (datatypeSize == 8) {
738                    log.trace("toNative(): CLASS_INT-ENUM is H5T_NATIVE_INT64");
739                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT64);
740                }
741                else {
742                    log.trace("toNative(): CLASS_INT-ENUM is H5T_NATIVE_INT");
743                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT);
744                }
745
746                if (datatypeOrder == Datatype.ORDER_BE) {
747                    log.trace("toNative(): CLASS_INT-ENUM is H5T_ORDER_BE");
748                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
749                }
750                else if (datatypeOrder == Datatype.ORDER_LE) {
751                    log.trace("toNative(): CLASS_INT-ENUM is H5T_ORDER_LE");
752                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
753                }
754
755                if (datatypeSign == Datatype.SIGN_NONE) {
756                    log.trace("toNative(): CLASS_INT-ENUM is H5T_SGN_NONE");
757                    H5.H5Tset_sign(tid, HDF5Constants.H5T_SGN_NONE);
758                }
759                break;
760            case CLASS_FLOAT:
761                if (datatypeSize == 8) {
762                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_DOUBLE);
763                }
764                else {
765                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_FLOAT);
766                }
767
768                if (datatypeOrder == Datatype.ORDER_BE) {
769                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
770                }
771                else if (datatypeOrder == Datatype.ORDER_LE) {
772                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
773                }
774                break;
775            case CLASS_CHAR:
776                if (datatypeSign == Datatype.SIGN_NONE) {
777                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UCHAR);
778                }
779                else {
780                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_CHAR);
781                }
782                break;
783            case CLASS_STRING:
784                tid = H5.H5Tcopy(HDF5Constants.H5T_C_S1);
785                if (isVLEN || datatypeSize < 0)
786                    H5.H5Tset_size(tid, HDF5Constants.H5T_VARIABLE);
787                else
788                    H5.H5Tset_size(tid, datatypeSize);
789
790                log.trace("toNative(): isVlenStr={}", isVLEN);
791                // H5.H5Tset_strpad(tid, HDF5Constants.H5T_STR_NULLPAD);
792                break;
793            case CLASS_REFERENCE:
794                if (datatypeSize > H5.H5Tget_size(HDF5Constants.H5T_STD_REF_OBJ)) {
795                    tid = H5.H5Tcopy(HDF5Constants.H5T_STD_REF_DSETREG);
796                }
797                else {
798                    tid = H5.H5Tcopy(HDF5Constants.H5T_STD_REF_OBJ);
799                }
800                break;
801            case CLASS_VLEN:
802                if (baseType != null) {
803                    if ((tmptid = baseType.toNative()) >= 0) {
804                        try {
805                            tid = H5.H5Tvlen_create(tmptid);
806                        }
807                        finally {
808                            close(tmptid);
809                        }
810                    }
811                }
812                else {
813                    log.debug("toNative(): CLASS_VLEN base type is NULL");
814                }
815                break;
816            case CLASS_BITFIELD:
817            case CLASS_OPAQUE:
818                if (datatypeSize == 1) {
819                    log.trace("toNative(): CLASS_BITFIELD-OPAQUE is H5T_NATIVE_INT8");
820                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8);
821                }
822                else if (datatypeSize == 2) {
823                    log.trace("toNative(): CLASS_BITFIELD-OPAQUE is H5T_NATIVE_INT16");
824                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT16);
825                }
826                else if (datatypeSize == 4) {
827                    log.trace("toNative(): CLASS_BITFIELD-OPAQUE is H5T_NATIVE_INT32");
828                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32);
829                }
830                else if (datatypeSize == 8) {
831                    log.trace("toNative(): CLASS_BITFIELD-OPAQUE is H5T_NATIVE_INT64");
832                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT64);
833                }
834                else {
835                    log.trace("toNative(): CLASS_BITFIELD-OPAQUE is H5T_NATIVE_INT");
836                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT);
837                }
838
839                if (datatypeOrder == Datatype.ORDER_BE) {
840                    log.trace("toNative(): CLASS_BITFIELD-OPAQUE is H5T_ORDER_BE");
841                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
842                }
843                else if (datatypeOrder == Datatype.ORDER_LE) {
844                    log.trace("toNative(): CLASS_BITFIELD-OPAQUE is H5T_ORDER_LE");
845                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
846                }
847                break;
848            default:
849                log.debug("toNative(): Unknown class");
850                break;
851            } // switch (tclass)
852        }
853        catch (Exception ex) {
854            log.debug("toNative(): Error figuring the datatype: ", ex);
855            tid = -1;
856        }
857
858        // set up enum members
859        if (datatypeClass == CLASS_ENUM) {
860            int ptid = tid;
861            try {
862                tid = H5.H5Tenum_create(ptid);
863                datatypeSize = H5.H5Tget_size(tid);
864            }
865            catch (Exception ex) {
866                log.debug("toNative(): create members failure: ", ex);
867                tid = -1;
868            }
869
870            try {
871                String memstr, memname;
872                int idx;
873                byte[] memval = null;
874                if (datatypeSize == 1) {
875                    memval = HDFNativeData.byteToByte(new Byte((byte) 0));
876                }
877                else if (datatypeSize == 2) {
878                    memval = HDFNativeData.shortToByte(new Short((short) 0));
879                }
880                else if (datatypeSize == 4) {
881                    memval = HDFNativeData.intToByte(new Integer((int) 0));
882                }
883                else if (datatypeSize == 8) {
884                    memval = HDFNativeData.longToByte(new Long((long) 0));
885                }
886                StringTokenizer token;
887
888                // using "0" and "1" as default
889                if (enumMembers == null) {
890                    token = new StringTokenizer("0,1", ",");
891                    log.trace("toNative(): default string");
892                }
893                else {
894                    token = new StringTokenizer(enumMembers, ",");
895                    log.trace("toNative(): string {}", enumMembers);
896                }
897
898                while (token.hasMoreTokens()) {
899                    memstr = token.nextToken();
900
901                    if (memstr != null) {
902                        memstr = memstr.trim();
903                    }
904
905                    if ((memstr == null) || (memstr.length() < 1)) {
906                        continue;
907                    }
908
909                    idx = memstr.indexOf('=');
910                    if (idx > 0) {
911                        memname = memstr.substring(0, idx);
912                        if (datatypeSize == 1) {
913                            log.trace("toNative(): ENUM is H5T_NATIVE_INT8");
914                            Byte tval = Byte.parseByte(memstr.substring(idx + 1));
915                            memval = HDFNativeData.byteToByte(tval);
916                        }
917                        else if (datatypeSize == 2) {
918                            log.trace("toNative(): CLASS_INT-ENUM is H5T_NATIVE_INT16");
919                            Short tval = Short.parseShort(memstr.substring(idx + 1));
920                            memval = HDFNativeData.shortToByte(tval);
921                        }
922                        else if (datatypeSize == 4) {
923                            log.trace("toNative(): CLASS_INT-ENUM is H5T_NATIVE_INT32");
924                            Integer tval = Integer.parseInt(memstr.substring(idx + 1));
925                            memval = HDFNativeData.intToByte(tval);
926                        }
927                        else if (datatypeSize == 8) {
928                            log.trace("toNative(): CLASS_INT-ENUM is H5T_NATIVE_INT64");
929                            Long tval = Long.parseLong(memstr.substring(idx + 1));
930                            memval = HDFNativeData.longToByte(tval);
931                        }
932                        else {
933                            log.debug("toNative(): enum datatypeSize incorrect");
934                        }
935                    }
936                    else {
937                        memname = memstr;
938                        if (datatypeSize == 1) {
939                            log.trace("toNative(): ENUM is H5T_NATIVE_INT8");
940                            Byte tval = new Byte(memval[0]);
941                            tval++;
942                            memval = HDFNativeData.byteToByte(tval);
943                        }
944                        else if (datatypeSize == 2) {
945                            log.trace("toNative(): CLASS_INT-ENUM is H5T_NATIVE_INT16");
946                            Short tval = (HDFNativeData.byteToShort(memval))[0];
947                            tval++;
948                            memval = HDFNativeData.shortToByte(tval);
949                        }
950                        else if (datatypeSize == 4) {
951                            log.trace("toNative(): CLASS_INT-ENUM is H5T_NATIVE_INT32");
952                            Integer tval = (HDFNativeData.byteToInt(memval))[0];
953                            tval++;
954                            memval = HDFNativeData.intToByte(tval);
955                        }
956                        else if (datatypeSize == 8) {
957                            log.trace("toNative(): CLASS_INT-ENUM is H5T_NATIVE_INT64");
958                            Long tval = (HDFNativeData.byteToLong(memval))[0];
959                            tval++;
960                            memval = HDFNativeData.longToByte(tval);
961                        }
962                        else {
963                            log.debug("toNative(): enum datatypeSize incorrect");
964                        }
965                    }
966                    log.trace("toNative(): H5Tenum_insert {} {}", memname, memval);
967                    H5.H5Tenum_insert(tid, memname, memval);
968                }
969            }
970            catch (Exception ex) {
971                log.debug("toNative(): set up enum members failure: ", ex);
972            }
973
974            try {
975                H5.H5Tclose(ptid);
976            }
977            catch (Exception ex) {
978                log.debug("toNative(): H5Tclose(ptid {}) failure: ", ptid, ex);
979            }
980        } // if (datatypeClass == CLASS_ENUM) {
981
982        return tid;
983    }
984
985    /**
986     * Allocates a one-dimensional array of byte, short, int, long, float, double, or String to store data in memory.
987     *
988     * For example,
989     *
990     * <pre>
991     * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32);
992     * int[] data = (int[]) allocateArray(tid, 100);
993     * </pre>
994     *
995     * returns a 32-bit integer array of size 100.
996     *
997     * @param tid
998     *            the datatype id.
999     * @param size
1000     *            the total number of data points of the array.
1001     *
1002     * @return the array object if successful; otherwise, return null.
1003     *
1004     * @throws OutOfMemoryError
1005     *            If there is a failure.
1006     */
1007    public static Object allocateArray(int tid, int size) throws OutOfMemoryError {
1008        log.trace("allocateArray(): start: tid={} size={}", tid, size);
1009        Object data = null;
1010        boolean isVL = false;
1011        boolean is_variable_str = false;
1012        boolean is_reg_ref = false;
1013
1014        if (size < 0) {
1015            log.debug("allocateArray(): size < 0");
1016            log.trace("allocateArray(): finish");
1017            return null;
1018        }
1019
1020        // Scalar members have dimensionality zero, i.e. size =0
1021        // what can we do about it, set the size to 1
1022        if (size == 0) {
1023            size = 1;
1024        }
1025
1026        // data type information
1027        int tclass = -1;
1028        int tsize = -1;
1029
1030        try {
1031            tclass = H5.H5Tget_class(tid);
1032            tsize = H5.H5Tget_size(tid);
1033            log.trace("allocateArray(): tclass={} : tsize={}", tclass, tsize);
1034        }
1035        catch (Exception ex) {
1036            log.debug("allocateArray(): H5Tget_xxxx data type information failure: ", ex);
1037        }
1038
1039        try {
1040            is_variable_str = H5.H5Tis_variable_str(tid);
1041        }
1042        catch (Exception ex) {
1043            log.debug("allocateArray(): H5Tis_variable_str(tid {}) failure: ", tid, ex);
1044        }
1045        isVL = (tclass == HDF5Constants.H5T_VLEN);
1046
1047        try {
1048            is_reg_ref = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG);
1049        }
1050        catch (Exception ex) {
1051            log.debug("allocateArray(): H5Tequal(tid {}, HDF5Constants.H5T_STD_REF_DSETREG) failure: ", tid, ex);
1052        }
1053
1054        if (is_variable_str || isVL || is_reg_ref) {
1055            log.trace("allocateArray(): is_variable_str={} || isVL={} || is_reg_ref={}", is_variable_str, isVL, is_reg_ref);
1056            data = new String[size];
1057            for (int i = 0; i < size; i++) {
1058                ((String[]) data)[i] = "";
1059            }
1060        }
1061        else if (tclass == HDF5Constants.H5T_INTEGER) {
1062            log.trace("allocateArray(): class.H5T_INTEGER={}", tclass);
1063            if (tsize == 1) {
1064                data = new byte[size];
1065            }
1066            else if (tsize == 2) {
1067                data = new short[size];
1068            }
1069            else if (tsize == 4) {
1070                data = new int[size];
1071            }
1072            else if (tsize == 8) {
1073                data = new long[size];
1074            }
1075        }
1076        else if (tclass == HDF5Constants.H5T_ENUM) {
1077            log.trace("allocateArray(): class.H5T_ENUM={}", tclass);
1078            int superTid = -1;
1079            try {
1080                superTid = H5.H5Tget_super(tid);
1081                data = allocateArray(superTid, size);
1082            }
1083            catch (Exception ex) {
1084                log.debug("allocateArray(): H5T_ENUM class enum data type information failure: ", ex);
1085            }
1086            finally {
1087                try {
1088                    H5.H5Tclose(superTid);
1089                }
1090                catch (Exception ex) {
1091                    log.debug("allocateArray(): H5T_ENUM H5Tclose(superTid {}) failure: ", superTid, ex);
1092                }
1093            }
1094        }
1095        else if (tclass == HDF5Constants.H5T_COMPOUND) {
1096            log.trace("allocateArray(): class.H5T_COMPOUND={}", tclass);
1097            return new byte[size];
1098        }
1099        else if (tclass == HDF5Constants.H5T_FLOAT) {
1100            log.trace("allocateArray(): class.H5T_FLOAT={}", tclass);
1101            if (tsize == 4) {
1102                data = new float[size];
1103            }
1104            else if (tsize == 8) {
1105                data = new double[size];
1106            }
1107        }
1108        else if ((tclass == HDF5Constants.H5T_STRING) || (tclass == HDF5Constants.H5T_REFERENCE)) {
1109            log.trace("allocateArray(): class.H5T_STRING || H5T_REFERENCE={}", tclass);
1110            data = new byte[size * tsize];
1111        }
1112        else if (tclass == HDF5Constants.H5T_ARRAY) {
1113            // use the base datatype to define the array
1114            int superTid = -1;
1115            try {
1116                int mn = H5.H5Tget_array_ndims(tid);
1117                long[] marray = new long[mn];
1118                H5.H5Tget_array_dims(tid, marray);
1119                int asize = 1;
1120                for (int j = 0; j < mn; j++) {
1121                    asize *= marray[j];
1122                }
1123                log.trace("allocateArray(): class.H5T_ARRAY={} : members={} : asize={}", tclass, mn, asize);
1124
1125                superTid = H5.H5Tget_super(tid);
1126                data = allocateArray(superTid, size * asize);
1127            }
1128            catch (Exception ex) {
1129                log.debug("allocateArray(): H5T_ARRAY class failure: ", ex);
1130            }
1131            finally {
1132                try {
1133                    H5.H5Tclose(superTid);
1134                }
1135                catch (Exception ex) {
1136                    log.debug("allocateArray(): H5T_ARRAY H5Tclose(superTid {}) failure: ", superTid, ex);
1137                }
1138            }
1139        }
1140        else if ((tclass == HDF5Constants.H5T_OPAQUE) || (tclass == HDF5Constants.H5T_BITFIELD)) {
1141            log.trace("allocateArray(): class.H5T_OPAQUE || H5T_BITFIELD={}", tclass);
1142            data = new byte[size * tsize];
1143        }
1144        else {
1145            log.debug("allocateArray(): class.????={}", tclass);
1146            data = null;
1147        }
1148
1149        return data;
1150    }
1151
1152    /**
1153     * Returns the size (in bytes) of a given datatype identifier.
1154     * <p>
1155     * It basically just calls H5Tget_size(tid).
1156     *
1157     * @param tid
1158     *            The datatype identifier.
1159     *
1160     * @return The size of the datatype in bytes.
1161     *
1162     * @see hdf.hdf5lib.H5#H5Tget_size(int)
1163     */
1164    public static final int getDatatypeSize(int tid) {
1165        // data type information
1166        int tsize = -1;
1167
1168        try {
1169            tsize = H5.H5Tget_size(tid);
1170        }
1171        catch (Exception ex) {
1172            tsize = -1;
1173        }
1174
1175        return tsize;
1176    }
1177
1178    /*
1179     * (non-Javadoc)
1180     *
1181     * @see hdf.object.Datatype#getDatatypeDescription()
1182     */
1183    @Override
1184    public String getDatatypeDescription() {
1185        if (description == null) {
1186            int tid = toNative();
1187            if (tid >= 0) {
1188                description = getDatatypeDescription(tid);
1189                close(tid);
1190            }
1191            else {
1192                description = "Unknown";
1193            }
1194        }
1195
1196        return description;
1197    }
1198
1199    /**
1200     * Returns a short description of a given datatype ID.
1201     *
1202     * @param tid
1203     *            the HDF5 datatype identifier
1204     *
1205     * @return a string describing the data type.
1206     */
1207    public static final String getDatatypeDescription(int tid) {
1208        log.trace("getDatatypeDescription(): start");
1209        String description = "Unknown";
1210
1211        // data type information
1212        int tclass = -1;
1213        int tsize = -1;
1214        int tsign = -1;
1215
1216        try {
1217            tclass = H5.H5Tget_class(tid);
1218            tsize = H5.H5Tget_size(tid);
1219        }
1220        catch (Exception ex) {
1221            log.debug("getDatatypeDescription(): Unknown: ", ex);
1222        }
1223
1224        if (tclass == HDF5Constants.H5T_INTEGER) {
1225            log.trace("getDatatypeDescription(): class H5T_INTEGER");
1226            try {
1227                tsign = H5.H5Tget_sign(tid);
1228            }
1229            catch (Exception ex) {
1230                log.debug("getDatatypeDescription(): H5Tget_sign(tid {}) failure:", tid, ex);
1231            }
1232            if (tsize == 1) {
1233                try {
1234                    if (tsign == HDF5Constants.H5T_SGN_NONE) {
1235                        description = "8-bit unsigned integer";
1236                    }
1237                    else {
1238                        description = "8-bit integer";
1239                    }
1240                }
1241                catch (Exception ex) {
1242                    description = "Unknown";
1243                }
1244            }
1245            else if (tsize == 2) {
1246                if (tsign == HDF5Constants.H5T_SGN_NONE) {
1247                    description = "16-bit unsigned integer";
1248                }
1249                else {
1250                    description = "16-bit integer";
1251                }
1252            }
1253            else if (tsize == 4) {
1254                if (tsign == HDF5Constants.H5T_SGN_NONE) {
1255                    description = "32-bit unsigned integer";
1256                }
1257                else {
1258                    description = "32-bit integer";
1259                }
1260            }
1261            else if (tsize == 8) {
1262                if (tsign == HDF5Constants.H5T_SGN_NONE) {
1263                    description = "64-bit unsigned integer";
1264                }
1265                else {
1266                    description = "64-bit integer";
1267                }
1268            }
1269        }
1270        else if (tclass == HDF5Constants.H5T_FLOAT) {
1271            log.trace("getDatatypeDescription(): class H5T_FLOAT");
1272            if (tsize == 4) {
1273                description = "32-bit floating-point";
1274            }
1275            else if (tsize == 8) {
1276                description = "64-bit floating-point";
1277            }
1278        }
1279        else if (tclass == HDF5Constants.H5T_STRING) {
1280            log.trace("getDatatypeDescription(): class H5T_STRING");
1281            try {
1282                if (H5.H5Tis_variable_str(tid)) {
1283                    description = "String, length = variable";
1284                }
1285                else {
1286                    description = "String, length = " + H5.H5Tget_size(tid);
1287                }
1288            }
1289            catch (Exception ex) {
1290                description = "String";
1291            }
1292        }
1293        else if (tclass == HDF5Constants.H5T_REFERENCE) {
1294            log.trace("getDatatypeDescription(): class H5T_REFERENCE");
1295            boolean is_reg_ref = false;
1296            try {
1297                is_reg_ref = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG);
1298            }
1299            catch (Exception ex) {
1300                log.debug("getDatatypeDescription(): H5T_STD_REF_DSETREG: ", ex);
1301            }
1302
1303            if (is_reg_ref) {
1304                description = "Dataset region reference";
1305            }
1306            else {
1307                description = "Object reference";
1308            }
1309        }
1310        else if (tclass == HDF5Constants.H5T_BITFIELD) {
1311            log.trace("getDatatypeDescription(): class H5T_BITFIELD");
1312            description = "Bitfield";
1313        }
1314        else if (tclass == HDF5Constants.H5T_ENUM) {
1315            log.trace("getDatatypeDescription(): class H5T_ENUM");
1316            byte[] evalue = new byte[tsize];
1317            String enames = " ( ";
1318            try {
1319                int n = H5.H5Tget_nmembers(tid);
1320                for (int i = 0; i < n; i++) {
1321                    H5.H5Tget_member_value(tid, i, evalue);
1322                    enames += H5.H5Tget_member_name(tid, i);
1323                    enames += "=";
1324                    if (tsize == 1) {
1325                        description = "8-bit enum";
1326                        enames += (HDFNativeData.byteToByte(evalue[0]))[0];
1327                    }
1328                    else if (tsize == 2) {
1329                        description = "16-bit enum";
1330                        enames += (HDFNativeData.byteToShort(evalue))[0];
1331                    }
1332                    else if (tsize == 4) {
1333                        description = "32-bit enum";
1334                        enames += (HDFNativeData.byteToInt(evalue))[0];
1335                    }
1336                    else if (tsize == 8) {
1337                        description = "64-bit enum";
1338                        enames += (HDFNativeData.byteToLong(evalue))[0];
1339                    }
1340                    if(i < n-1)
1341                        enames += " ";
1342                }
1343                enames += ")";
1344                description += enames;
1345            }
1346            catch (Exception ex) {
1347                log.debug("getDatatypeDescription(): H5T_ENUM: ", ex);
1348            }
1349        }
1350        else if (tclass == HDF5Constants.H5T_ARRAY) {
1351            log.trace("getDatatypeDescription(): class H5T_ARRAY");
1352            description = "Array of ";
1353            // use the base datatype to define the array
1354            int tmptid = -1;
1355            try {
1356                tmptid = H5.H5Tget_super(tid);
1357                description += getDatatypeDescription(tmptid);
1358                int ndims = H5.H5Tget_array_ndims(tid);
1359                long adims[] = new long[ndims];
1360                try {
1361                    H5.H5Tget_array_dims(tid, adims);
1362                }
1363                catch (Exception ex) {
1364                    log.debug("getDatatypeDescription(): H5T_ARRAY dims: ", ex);
1365                }
1366
1367                description += " (" + adims[0];
1368                for (int j = 1; j < ndims; j++)
1369                    description += "x" + adims[j];
1370                description += ")";
1371            }
1372            catch (Exception ex) {
1373                log.debug("getDatatypeDescription(): H5T_ARRAY: ", ex);
1374            }
1375            finally {
1376                try {
1377                    H5.H5Tclose(tmptid);
1378                }
1379                catch (Exception ex) {
1380                    log.debug("getDatatypeDescription(): H5T_ARRAY H5Tclose(tmptid {}) failure: ", tmptid, ex);
1381                }
1382            }
1383        }
1384        else if (tclass == HDF5Constants.H5T_COMPOUND) {
1385            log.trace("getDatatypeDescription(): class H5T_COMPOUND");
1386            description = "Compound ";
1387            try {
1388                description += "{";
1389                int n = H5.H5Tget_nmembers(tid);
1390                int mtid = -1;
1391
1392                for (int i = 0; i < n; i++) {
1393                    mtid = H5.H5Tget_member_type(tid, i);
1394                    description += getDatatypeDescription(mtid) + ", ";
1395                    try {
1396                        H5.H5Tclose(mtid);
1397                    }
1398                    catch (Exception ex2) {
1399                        log.debug("getDatatypeDescription(): H5T_COMPOUND H5Tclose(mtid {}) failure: ", mtid, ex2);
1400                    }
1401                    mtid = -1;
1402                }
1403                description += "}";
1404            }
1405            catch (Exception ex) {
1406                log.debug("getDatatypeDescription(): H5T_COMPOUND: ", ex);
1407            }
1408        }
1409        else if (tclass == HDF5Constants.H5T_VLEN) {
1410            log.trace("getDatatypeDescription(): class H5T_VLEN");
1411            int tmptid = -1;
1412            try {
1413                tmptid = H5.H5Tget_super(tid);
1414                description = "Variable-length of " + getDatatypeDescription(tmptid);
1415            }
1416            catch (Exception ex) {
1417                description = "Variable-length";
1418            }
1419            finally {
1420                try {
1421                    H5.H5Tclose(tmptid);
1422                }
1423                catch (Exception ex) {
1424                    log.debug("getDatatypeDescription(): H5T_VLEN H5Tclose(tmptid {}) failure: ", tmptid, ex);
1425                }
1426            }
1427        }
1428        else if (tclass == HDF5Constants.H5T_OPAQUE) {
1429            log.trace("getDatatypeDescription(): class H5T_OPAQUE");
1430            description = "Opaque";
1431        }
1432        else {
1433            description = "Unknown";
1434        }
1435
1436        log.trace("getDatatypeDescription(): finish");
1437        return description;
1438    }
1439
1440    /*
1441     * (non-Javadoc)
1442     *
1443     * @see hdf.object.Datatype#isUnsigned()
1444     */
1445    @Override
1446    public boolean isUnsigned() {
1447        boolean unsigned = false;
1448        int tid = -1;
1449
1450        if (datatypeClass == Datatype.CLASS_COMPOUND) return false;
1451
1452        tid = toNative();
1453
1454        if (tid >= 0) {
1455            unsigned = isUnsigned(tid);
1456            try {
1457                H5.H5Tclose(tid);
1458            }
1459            catch (final Exception ex) {
1460            }
1461        }
1462
1463        return unsigned;
1464    }
1465
1466    /**
1467     * Checks if a datatype specified by the identifier is an unsigned integer.
1468     *
1469     * @param tid
1470     *            the datatype ID to be checked.
1471     *
1472     * @return true is the datatype is an unsigned integer; otherwise returns false.
1473     */
1474    public static final boolean isUnsigned(int tid) {
1475        boolean unsigned = false;
1476
1477        if (tid >= 0) {
1478            try {
1479                int tclass = H5.H5Tget_class(tid);
1480                log.trace("isUnsigned(): tclass = {}", tclass);
1481                if (tclass != HDF5Constants.H5T_FLOAT && tclass != HDF5Constants.H5T_STRING
1482                        && tclass != HDF5Constants.H5T_REFERENCE && tclass != HDF5Constants.H5T_BITFIELD
1483                        && tclass != HDF5Constants.H5T_OPAQUE
1484                        && tclass != HDF5Constants.H5T_COMPOUND) {
1485                    int tsign = H5.H5Tget_sign(tid);
1486                    if (tsign == HDF5Constants.H5T_SGN_NONE) {
1487                        unsigned = true;
1488                    }
1489                    else {
1490                        log.trace("isUnsigned(): not unsigned");
1491                    }
1492                }
1493                else {
1494                    log.trace("isUnsigned(): tclass not integer type");
1495                }
1496            }
1497            catch (Exception ex) {
1498                log.debug("isUnsigned(): {} Datatype {} failure", getDatatypeDescription(tid), tid, ex);
1499                unsigned = false;
1500            }
1501        }
1502        else {
1503            log.trace("isUnsigned(): not a valid datatype");
1504        }
1505
1506        return unsigned;
1507    }
1508
1509    /**
1510     * Checks if a datatype is variable-length.
1511     *
1512     * @return if the datatype is variable-length.
1513     */
1514    public boolean isVLEN() {
1515        return isVLEN;
1516    }
1517
1518    /**
1519     * Opens access to a named datatype.
1520     * <p>
1521     * It calls H5.H5Topen(loc, name).
1522     *
1523     * @return the datatype identifier if successful; otherwise returns negative value.
1524     *
1525     * @see hdf.hdf5lib.H5#H5Topen(int, String)
1526     */
1527    @Override
1528    public int open() {
1529        log.trace("open(): start");
1530        int tid = -1;
1531
1532        try {
1533            tid = H5.H5Topen(getFID(), getPath() + getName(), HDF5Constants.H5P_DEFAULT);
1534        }
1535        catch (HDF5Exception ex) {
1536            tid = -1;
1537        }
1538
1539        log.trace("open(): finish");
1540        return tid;
1541    }
1542
1543    /**
1544     * Closes a datatype identifier.
1545     * <p>
1546     * It calls H5.H5close(tid).
1547     *
1548     * @param tid
1549     *            the datatype ID to close
1550     */
1551    @Override
1552    public void close(int tid) {
1553        try {
1554            H5.H5Tclose(tid);
1555        }
1556        catch (HDF5Exception ex) {
1557            log.debug("close(): H5Tclose(tid {}) failure: ", tid, ex);
1558        }
1559    }
1560
1561    /*
1562     * (non-Javadoc)
1563     *
1564     * @see hdf.object.Datatype#getMetadata()
1565     */
1566    @Override
1567    public List<Attribute> getMetadata() throws HDF5Exception {
1568        return this.getMetadata(fileFormat.getIndexType(null), fileFormat.getIndexOrder(null));
1569    }
1570
1571    /*
1572     * (non-Javadoc)
1573     *
1574     * @see hdf.object.DataFormat#getMetadata(int...)
1575     */
1576    public List<Attribute> getMetadata(int... attrPropList) throws HDF5Exception {
1577        log.trace("getMetadata(): start");
1578        // load attributes first
1579        if (attributeList == null) {
1580            int tid = open();
1581            int indxType = fileFormat.getIndexType(null);
1582            int order = fileFormat.getIndexOrder(null);
1583
1584            if (attrPropList.length > 0) {
1585                indxType = attrPropList[0];
1586                if (attrPropList.length > 1) {
1587                    order = attrPropList[1];
1588                }
1589            }
1590
1591            try {
1592                attributeList = H5File.getAttribute(tid, indxType, order);
1593            }
1594            catch (Exception ex) {
1595                log.debug("getMetadata(): H5File.getAttribute failure: ", ex);
1596            }
1597            finally {
1598                close(tid);
1599            }
1600        } // if (attributeList == null)
1601
1602        try {
1603            this.linkTargetObjName = H5File.getLinkTargetName(this);
1604        }
1605        catch (Exception ex) {
1606            log.debug("getMetadata(): H5File.linkTargetObjName failure: ", ex);
1607        }
1608
1609        log.trace("getMetadata(): finish");
1610        return attributeList;
1611    }
1612
1613    /*
1614     * (non-Javadoc)
1615     *
1616     * @see hdf.object.Datatype#writeMetadata(java.lang.Object)
1617     */
1618    @Override
1619    public void writeMetadata(Object info) throws Exception {
1620        log.trace("writeMetadata(): start");
1621
1622        // only attribute metadata is supported.
1623        if (!(info instanceof Attribute)) {
1624            log.debug("writeMetadata(): Object not an Attribute");
1625            log.trace("writeMetadata(): finish");
1626            return;
1627        }
1628
1629        boolean attrExisted = false;
1630        Attribute attr = (Attribute) info;
1631
1632        if (attributeList == null) {
1633            this.getMetadata();
1634        }
1635
1636        if (attributeList != null)
1637            attrExisted = attributeList.contains(attr);
1638
1639        getFileFormat().writeAttribute(this, attr, attrExisted);
1640
1641        // add the new attribute into attribute list
1642        if (!attrExisted) {
1643            attributeList.add(attr);
1644            nAttributes = attributeList.size();
1645        }
1646        log.trace("writeMetadata(): finish");
1647    }
1648
1649    /*
1650     * (non-Javadoc)
1651     *
1652     * @see hdf.object.Datatype#removeMetadata(java.lang.Object)
1653     */
1654    @Override
1655    public void removeMetadata(Object info) throws HDF5Exception {
1656        log.trace("removeMetadata(): start");
1657
1658        // only attribute metadata is supported.
1659        if (!(info instanceof Attribute)) {
1660            log.debug("removeMetadata(): Object not an attribute");
1661            log.trace("removeMetadata(): finish");
1662            return;
1663        }
1664
1665        Attribute attr = (Attribute) info;
1666        int tid = open();
1667        try {
1668            H5.H5Adelete(tid, attr.getName());
1669            List<Attribute> attrList = getMetadata();
1670            attrList.remove(attr);
1671            nAttributes = attributeList.size();
1672        }
1673        catch (Exception ex) {
1674            log.debug("removeMetadata(): ", ex);
1675        }
1676        finally {
1677            close(tid);
1678        }
1679        log.trace("removeMetadata(): finish");
1680    }
1681
1682    public void setName(String newName) throws Exception {
1683        H5File.renameObject(this, newName);
1684        super.setName(newName);
1685    }
1686}