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