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