001/*****************************************************************************
002 * Copyright by The HDF Group.                                               *
003 * Copyright by the Board of Trustees of the University of Illinois.         *
004 * All rights reserved.                                                      *
005 *                                                                           *
006 * This file is part of the HDF Java Products distribution.                  *
007 * The full copyright notice, including terms governing use, modification,   *
008 * and redistribution, is contained in the files COPYING and Copyright.html. *
009 * COPYING can be found at the root of the source code distribution tree.    *
010 * Or, see https://support.hdfgroup.org/products/licenses.html               *
011 * If you do not have access to either file, you may request a copy from     *
012 * help@hdfgroup.org.                                                        *
013 ****************************************************************************/
014
015package hdf.object.h5;
016
017import java.lang.reflect.Array;
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.Iterator;
021import java.util.List;
022import java.util.Map.Entry;
023import java.util.Objects;
024import java.util.Vector;
025
026import hdf.hdf5lib.H5;
027import hdf.hdf5lib.HDF5Constants;
028import hdf.hdf5lib.HDFNativeData;
029import hdf.hdf5lib.exceptions.HDF5Exception;
030import hdf.hdf5lib.exceptions.HDF5LibraryException;
031import hdf.hdf5lib.structs.H5O_info_t;
032import hdf.object.Attribute;
033import hdf.object.CompoundDS;
034import hdf.object.Datatype;
035import hdf.object.FileFormat;
036
037/**
038 * This class defines HDF5 datatype characteristics and APIs for a data type.
039 * <p>
040 * This class provides several methods to convert an HDF5 datatype identifier to a datatype object, and vice versa. A
041 * datatype object is described by four basic fields: datatype class, size, byte order, and sign, while an HDF5 datatype
042 * is presented by a datatype identifier.
043 *
044 * @version 1.1 9/4/2007
045 * @author Peter X. Cao
046 */
047public class H5Datatype extends Datatype {
048    private static final long serialVersionUID = -750546422258749792L;
049
050    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(H5Datatype.class);
051
052    /**
053     * The list of attributes of this data object.
054     */
055    private List<Attribute> attributeList;
056
057    private boolean isRefObj = false;
058
059    private boolean isRegRef = false;
060
061    private int nAttributes = -1;
062
063    private H5O_info_t objInfo;
064
065    /**
066     * The native class of the datatype.
067     */
068    private int nativeClass = -1;
069
070    /**
071     * The native properties of the number datatype.
072     */
073    private long nativePrecision = 0;
074    private int nativeOffset = -1;
075    private int nativePadLSB = -1;
076    private int nativePadMSB = -1;
077
078    /**
079     * The native properties of the float datatype.
080     */
081    private long nativeFPebias = 0;
082    private long nativeFPspos = -1;
083    private long nativeFPepos = -1;
084    private long nativeFPesize = -1;
085    private long nativeFPmpos = -1;
086    private long nativeFPmsize = -1;
087    private int nativeFPnorm = -1;
088    private int nativeFPinpad = -1;
089
090    /**
091     * The native properties of the string datatype.
092     */
093    private int nativeStrPad = -1;
094    private int nativeStrCSET = -1;
095
096    /**
097     * The tag for an opaque datatype.
098     */
099    private String opaqueTag = null;
100
101    /**
102     * Constructs an named HDF5 data type object for a given file, dataset name and group path.
103     * <p>
104     * The datatype object represents an existing named datatype in file. For example,
105     *
106     * <pre>
107     * new H5Datatype(file, "dtype1", "/g0")
108     * </pre>
109     *
110     * constructs a datatype object that corresponds to the dataset,"dset1", at group "/g0".
111     *
112     * @param theFile
113     *            the file that contains the datatype.
114     * @param name
115     *            the name of the dataset such as "dset1".
116     * @param path
117     *            the group path to the dataset such as "/g0/".
118     */
119    public H5Datatype(FileFormat theFile, String name, String path) {
120        this(theFile, name, path, null);
121    }
122
123    /**
124     * @deprecated Not for public use in the future. <br>
125     *             Using {@link #H5Datatype(FileFormat, String, String)}
126     *
127     * @param theFile
128     *            the file that contains the datatype.
129     * @param name
130     *            the name of the dataset such as "dset1".
131     * @param path
132     *            the group path to the dataset such as "/g0/".
133     * @param oid
134     *            the oid of the dataset.
135     */
136    @Deprecated
137    public H5Datatype(FileFormat theFile, String name, String path, long[] oid) {
138        super(theFile, name, path, oid);
139        objInfo = new H5O_info_t(-1L, -1L, 0, 0, -1L, 0L, 0L, 0L, 0L, null, null, null);
140
141        if (theFile != null) {
142            if (oid == null) {
143                // retrieve the object ID
144                try {
145                    byte[] refBuf = H5.H5Rcreate(theFile.getFID(), this.getFullName(), HDF5Constants.H5R_OBJECT, -1);
146                    this.oid = new long[1];
147                    this.oid[0] = HDFNativeData.byteToLong(refBuf, 0);
148                }
149                catch (Exception ex) {
150                    log.debug("constructor ID {} for {} failed H5Rcreate", theFile.getFID(), this.getFullName());
151                }
152            }
153
154            long tid = -1;
155            try {
156                tid = H5.H5Topen(theFile.getFID(), this.getFullName(), HDF5Constants.H5P_DEFAULT);
157                fromNative(tid);
158            }
159            catch (Exception ex) {
160                log.debug("constructor H5Topen() failure");
161            }
162            finally {
163                close(tid);
164            }
165        }
166    }
167
168    /**
169     * Constructs a Datatype with specified class, size, byte order and sign.
170     * <p>
171     * The following is a list of a few examples of H5Datatype.
172     * <ol>
173     * <li>to create unsigned native integer<br>
174     * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
175     * <li>to create 16-bit signed integer with big endian<br>
176     * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
177     * <li>to create native float<br>
178     * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
179     * <li>to create 64-bit double<br>
180     * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
181     * </ol>
182     *
183     * @param tclass
184     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
185     * @param tsize
186     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
187     *            Valid values are NATIVE or a positive value. For string datatypes, -1 is also
188     *            a valid value (to create a variable-length string).
189     * @param torder
190     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
191     *            ORDER_NONE and NATIVE.
192     * @param tsign
193     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
194     *
195     * @throws Exception
196     *            if there is an error
197     */
198    public H5Datatype(int tclass, int tsize, int torder, int tsign) throws Exception {
199        this(tclass, tsize, torder, tsign, null);
200    }
201
202    /**
203     * Constructs a Datatype with specified class, size, byte order and sign.
204     * <p>
205     * The following is a list of a few examples of H5Datatype.
206     * <ol>
207     * <li>to create unsigned native integer<br>
208     * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
209     * <li>to create 16-bit signed integer with big endian<br>
210     * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
211     * <li>to create native float<br>
212     * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
213     * <li>to create 64-bit double<br>
214     * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
215     * </ol>
216     *
217     * @param tclass
218     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
219     * @param tsize
220     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4.
221     *            Valid values are NATIVE or a positive value. For string datatypes, -1 is also
222     *            a valid value (to create a variable-length string).
223     * @param torder
224     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
225     *            ORDER_NONE and NATIVE.
226     * @param tsign
227     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
228     * @param tbase
229     *            the base datatype of the new datatype
230     *
231     * @throws Exception
232     *            if there is an error
233     */
234    public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) throws Exception {
235        this(tclass, tsize, torder, tsign, tbase, null);
236    }
237
238    /**
239     * Constructs a Datatype with specified class, size, byte order and sign.
240     * <p>
241     * The following is a list of a few examples of H5Datatype.
242     * <ol>
243     * <li>to create unsigned native integer<br>
244     * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE);
245     * <li>to create 16-bit signed integer with big endian<br>
246     * H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2, Datatype.ORDER_BE, Datatype.NATIVE);
247     * <li>to create native float<br>
248     * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE);
249     * <li>to create 64-bit double<br>
250     * H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
251     * </ol>
252     *
253     * @param tclass
254     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
255     * @param tsize
256     *            the size of the datatype in bytes, e.g. for a 32-bit integer, the
257     *            size is 4. Valid values are NATIVE or a positive value. For string
258     *            datatypes, -1 is also a valid value (to create a variable-length
259     *            string).
260     * @param torder
261     *            the byte order of the datatype. Valid values are ORDER_LE,
262     *            ORDER_BE, ORDER_VAX, ORDER_NONE and NATIVE.
263     * @param tsign
264     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and
265     *            NATIVE.
266     * @param tbase
267     *            the base datatype of the new datatype
268     * @param pbase
269     *            the parent datatype of the new datatype
270     *
271     * @throws Exception
272     *            if there is an error
273     */
274    public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase) throws Exception {
275        super(tclass, tsize, torder, tsign, tbase, pbase);
276        datatypeDescription = getDescription();
277    }
278
279    /**
280     * Constructs a Datatype with a given native datatype identifier.
281     * <p>
282     * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5,
283     *
284     * <pre>
285     * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
286     * Datatype dtype = new Datatype(tid);
287     * </pre>
288     *
289     * will construct a datatype equivalent to new Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, Datatype.SIGN_NONE);
290     *
291     * @see #fromNative(long nativeID)
292     *
293     * @param theFile
294     *            the file that contains the datatype.
295     * @param nativeID
296     *            the native datatype identifier.
297     *
298     * @throws Exception
299     *            if there is an error
300     */
301    public H5Datatype(FileFormat theFile, long nativeID) throws Exception {
302        this(theFile, nativeID, null);
303    }
304
305    /**
306     * Constructs a Datatype with a given native datatype identifier.
307     * <p>
308     * For example, if the datatype identifier is a 32-bit unsigned integer created from HDF5,
309     *
310     * <pre>
311     * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
312     * Datatype dtype = new Datatype(tid);
313     * </pre>
314     *
315     * will construct a datatype equivalent to new Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, Datatype.SIGN_NONE);
316     *
317     * @see #fromNative(long nativeID)
318     *
319     * @param theFile
320     *            the file that contains the datatype.
321     * @param nativeID
322     *            the native datatype identifier.
323     * @param pbase
324     *            the parent datatype of the new datatype
325     *
326     * @throws Exception
327     *            if there is an error
328     */
329    public H5Datatype(FileFormat theFile, long nativeID, Datatype pbase) throws Exception {
330        super(theFile, nativeID, pbase);
331        fromNative(nativeID);
332        datatypeDescription = getDescription();
333    }
334
335    /**
336     * Opens access to a named datatype.
337     * <p>
338     * It calls H5.H5Topen(loc, name).
339     *
340     * @return the datatype identifier if successful; otherwise returns negative value.
341     *
342     * @see hdf.hdf5lib.H5#H5Topen(long, String, long)
343     */
344    @Override
345    public long open() {
346        long tid = -1;
347
348        if (fileFormat != null) {
349            try {
350                tid = H5.H5Topen(getFID(), getFullName(), HDF5Constants.H5P_DEFAULT);
351            }
352            catch (HDF5Exception ex) {
353                tid = -1;
354            }
355        }
356
357        return tid;
358    }
359
360    /**
361     * Closes a datatype identifier.
362     * <p>
363     * It calls H5.H5close(tid).
364     *
365     * @param tid
366     *            the datatype ID to close
367     */
368    @Override
369    public void close(long tid) {
370        if (tid >= 0) {
371            try {
372                H5.H5Tclose(tid);
373            }
374            catch (HDF5Exception ex) {
375                log.debug("close(): H5Tclose(tid {}) failure: ", tid, ex);
376            }
377        }
378    }
379
380    /*
381     * (non-Javadoc)
382     *
383     * @see hdf.object.DataFormat#hasAttribute()
384     */
385    @Override
386    public boolean hasAttribute() {
387        log.trace("hasAttribute(): nAttributes={}", nAttributes);
388        objInfo.num_attrs = nAttributes;
389
390        if ((objInfo.num_attrs < 0) && (fileFormat != null)) {
391            long tid = -1;
392            try {
393                tid = H5.H5Topen(getFID(), getFullName(), HDF5Constants.H5P_DEFAULT);
394                fromNative(tid);
395                objInfo = H5.H5Oget_info(tid);
396            }
397            catch (Exception ex) {
398                objInfo.num_attrs = 0;
399            }
400            finally {
401                close(tid);
402            }
403            nAttributes = (int) objInfo.num_attrs;
404        }
405
406        log.trace("hasAttribute(): objInfo.num_attrs={}", objInfo.num_attrs);
407
408        return (objInfo.num_attrs > 0);
409    }
410
411    /**
412     * Converts values in an Enumeration Datatype to names.
413     * <p>
414     * This method searches the identified enumeration datatype for the values appearing in
415     * <code>inValues</code> and returns the names corresponding to those values. If a given value is
416     * not found in the enumeration datatype, the name corresponding to that value will be set to
417     * <code>"ENUM ERR value"</code> in the string array that is returned.
418     * <p>
419     * If the method fails in general, null will be returned instead of a String array. An empty
420     * <code>inValues</code> parameter would cause general failure.
421     *
422     * @param inValues
423     *            The array of enumerations values to be converted.
424     *
425     * @return The string array of names if successful; otherwise return null.
426     *
427     * @throws HDF5Exception
428     *             If there is an error at the HDF5 library level.
429     *
430     */
431    public String[] convertEnumValueToName(Object inValues) throws HDF5Exception {
432        log.trace("convertEnumValueToName() inValues={} start", inValues);
433
434        if (inValues == null) {
435            log.debug("convertEnumValueToName() failure: in values null ");
436            return null;
437        }
438
439        int inSize = 0;
440        String[] outNames = null;
441        String cName = inValues.getClass().getName();
442        boolean isArray = cName.lastIndexOf('[') >= 0;
443        if (isArray) {
444            inSize = Array.getLength(inValues);
445        }
446        else {
447            inSize = 1;
448        }
449
450        if (inSize <= 0) {
451            log.debug("convertEnumValueToName() failure: inSize length invalid");
452            log.debug("convertEnumValueToName(): inValues={} inSize={}", inValues, inSize);
453            return null;
454        }
455
456        if (enumMembers == null || enumMembers.size() <= 0) {
457            log.debug("convertEnumValueToName(): no members");
458            return null;
459        }
460
461        log.trace("convertEnumValueToName(): inSize={} nMembers={} enums={}", inSize, enumMembers.size(), enumMembers);
462        outNames = new String[inSize];
463        for (int i = 0; i < inSize; i++) {
464            if (isArray) {
465                if (enumMembers.containsKey(String.valueOf(Array.get(inValues, i)))) {
466                    outNames[i] = enumMembers.get(String.valueOf(Array.get(inValues, i)));
467                }
468                else {
469                    outNames[i] = "**ENUM ERR " + Array.get(inValues, i) + "**";
470                }
471            }
472            else {
473                if (enumMembers.containsKey(String.valueOf(inValues))) {
474                    outNames[i] = enumMembers.get(String.valueOf(inValues));
475                }
476                else {
477                    outNames[i] = "**ENUM ERR " + inValues + "**";
478                }
479            }
480        }
481
482        return outNames;
483    }
484
485    /**
486     * Converts names in an Enumeration Datatype to values.
487     * <p>
488     * This method searches the identified enumeration datatype for the names appearing in
489     * <code>inValues</code> and returns the values corresponding to those names.
490     *
491     * @param in
492     *            The array of enumerations names to be converted.
493     *
494     * @return The int array of values if successful; otherwise return null.
495     *
496     * @throws HDF5Exception
497     *             If there is an error at the HDF5 library level.
498     *
499     */
500    public Object[] convertEnumNameToValue(String[] in) throws HDF5Exception {
501        int size = 0;
502
503        if (in == null) {
504            log.debug("convertEnumNameToValue() failure: in values null");
505            return null;
506        }
507
508        if ((size = Array.getLength(in)) <= 0) {
509            log.debug("convertEnumNameToValue() failure: in size not valid");
510            return null;
511        }
512
513        if (enumMembers == null || enumMembers.size() <= 0) {
514            log.debug("convertEnumNameToValue(): no members");
515            return null;
516        }
517
518        Object[] out = null;
519        if (datatypeSize == 1) {
520            out = new Byte[size];
521        }
522        else if (datatypeSize == 2) {
523            out = new Short[size];
524        }
525        else if (datatypeSize == 4) {
526            out = new Integer[size];
527        }
528        else if (datatypeSize == 8) {
529            out = new Long[size];
530        }
531        else {
532            out = new Object[size];
533        }
534
535        for (int i = 0; i < size; i++) {
536            if (in[i] == null || in[i].length() <= 0)
537                continue;
538
539            for (Entry<String, String> entry : enumMembers.entrySet()) {
540                if (Objects.equals(in[i], entry.getValue())) {
541                    if (datatypeSize == 1) {
542                        log.trace("convertEnumNameToValue(): ENUM is H5T_NATIVE_INT8");
543                        out[i] = Byte.parseByte(entry.getKey());
544                    }
545                    else if (datatypeSize == 2) {
546                        log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT16");
547                        out[i] = Short.parseShort(entry.getKey());
548                    }
549                    else if (datatypeSize == 4) {
550                        log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT32");
551                        out[i] = Integer.parseInt(entry.getKey());
552                    }
553                    else if (datatypeSize == 8) {
554                        log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT64");
555                        out[i] = Long.parseLong(entry.getKey());
556                    }
557                    else {
558                        log.debug("convertEnumNameToValue(): enum datatypeSize incorrect");
559                        out[i] = -1;
560                    }
561                    break;
562                }
563            }
564        }
565
566        return out;
567    }
568
569    /*
570     * (non-Javadoc)
571     *
572     * @see hdf.object.Datatype#fromNative(int)
573     */
574    @Override
575    public void fromNative(long tid) {
576        log.trace("fromNative(): start: tid={}", tid);
577        long tsize = -1;
578        int torder = -1;
579        boolean isChar = false;
580        boolean isUchar = false;
581
582        if (tid < 0) {
583            datatypeClass = CLASS_NO_CLASS;
584        }
585        else {
586            try {
587                nativeClass = H5.H5Tget_class(tid);
588                tsize = H5.H5Tget_size(tid);
589                isVariableStr = H5.H5Tis_variable_str(tid);
590                isVLEN = false;
591                log.trace("fromNative(): tclass={}, tsize={}, torder={}, isVLEN={}", nativeClass, tsize, torder, isVLEN);
592                if (H5.H5Tcommitted(tid)) {
593                    isNamed = true;
594                    try {
595                        setFullname(null, H5.H5Iget_name(tid));
596                    }
597                    catch (Exception nex) {
598                        log.debug("fromNative(): setName failure: {}", nex.getMessage());
599                    }
600                    log.trace("fromNative(): path={} name={}", this.getPath(), this.getName());
601                }
602                log.trace("fromNative(): isNamed={}", isNamed());
603            }
604            catch (Exception ex) {
605                log.debug("fromNative(): failure: ", ex);
606                datatypeClass = CLASS_NO_CLASS;
607            }
608
609            try {
610                isUchar = H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_UCHAR);
611                isChar = (H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_CHAR) || isUchar);
612                log.trace("fromNative(): tclass={}, tsize={}, torder={}, isUchar={}, isChar={}", nativeClass, tsize, torder, isUchar, isChar);
613            }
614            catch (Exception ex) {
615                log.debug("fromNative(): native char type failure: ", ex);
616            }
617
618            datatypeOrder = HDF5Constants.H5T_ORDER_NONE;
619            if (datatypeIsAtomic(tid) || (nativeClass == HDF5Constants.H5T_COMPOUND)) {
620                try {
621                    torder = H5.H5Tget_order(tid);
622                    datatypeOrder = (torder == HDF5Constants.H5T_ORDER_BE) ? ORDER_BE : ORDER_LE;
623                }
624                catch (Exception ex) {
625                    log.debug("fromNative(): get_order failure: ", ex);
626                }
627            }
628
629            if (datatypeIsAtomic(tid)) {
630                try {
631                    nativePrecision = H5.H5Tget_precision_long(tid);
632                }
633                catch (Exception ex) {
634                    log.debug("fromNative(): get_precision failure: ", ex);
635                }
636
637                try {
638                    nativeOffset = H5.H5Tget_offset(tid);
639                }
640                catch (Exception ex) {
641                    log.debug("fromNative(): get_offset failure: ", ex);
642                }
643
644                try {
645                    int[] pads = new int[2];
646                    H5.H5Tget_pad(tid, pads);
647                    nativePadLSB = pads[0];
648                    nativePadMSB = pads[1];
649                }
650                catch (Exception ex) {
651                    log.debug("fromNative(): get_pad failure: ", ex);
652                }
653            }
654
655            log.trace("fromNative(): isUchar={}, nativePrecision={}, nativeOffset={}, nativePadLSB={}, nativePadMSB={}", isUchar, nativePrecision, nativeOffset, nativePadLSB,
656                    nativePadMSB);
657
658            datatypeSign = NATIVE; // default
659            if (nativeClass == HDF5Constants.H5T_ARRAY) {
660                long tmptid = -1;
661                datatypeClass = CLASS_ARRAY;
662                try {
663                    int ndims = H5.H5Tget_array_ndims(tid);
664                    arrayDims = new long[ndims];
665                    H5.H5Tget_array_dims(tid, arrayDims);
666
667                    tmptid = H5.H5Tget_super(tid);
668                    baseType = new H5Datatype(this.fileFormat, tmptid, this);
669                    if (baseType == null) {
670                        log.debug("fromNative(): ARRAY datatype has null base type");
671                        throw new Exception("Datatype (ARRAY) has no base datatype");
672                    }
673
674                    datatypeSign = baseType.getDatatypeSign();
675                }
676                catch (Exception ex) {
677                    log.debug("fromNative(): array type failure: ", ex);
678                }
679                finally {
680                    close(tmptid);
681                }
682            }
683            else if (nativeClass == HDF5Constants.H5T_COMPOUND) {
684                datatypeClass = CLASS_COMPOUND;
685
686                try {
687                    int nMembers = H5.H5Tget_nmembers(tid);
688                    compoundMemberNames = new Vector<>(nMembers);
689                    compoundMemberTypes = new Vector<>(nMembers);
690                    compoundMemberOffsets = new Vector<>(nMembers);
691                    log.trace("fromNative(): compound type nMembers={} start", nMembers);
692
693                    for (int i = 0; i < nMembers; i++) {
694                        String memberName = H5.H5Tget_member_name(tid, i);
695                        log.trace("fromNative(): compound type [{}] name={} start", i, memberName);
696                        long memberOffset = H5.H5Tget_member_offset(tid, i);
697                        long memberID = -1;
698                        H5Datatype membertype = null;
699                        try {
700                            memberID = H5.H5Tget_member_type(tid, i);
701                            membertype = new H5Datatype(this.fileFormat, memberID, this);
702                        }
703                        catch (Exception ex1) {
704                            log.debug("fromNative(): compound type failure: ", ex1);
705                        }
706                        finally {
707                            close(memberID);
708                        }
709
710                        compoundMemberNames.add(i, memberName);
711                        compoundMemberOffsets.add(i, memberOffset);
712                        compoundMemberTypes.add(i, membertype);
713                    }
714                }
715                catch (HDF5LibraryException ex) {
716                    log.debug("fromNative(): compound type failure: ", ex);
717                }
718            }
719            else if (nativeClass == HDF5Constants.H5T_INTEGER) {
720                datatypeClass = CLASS_INTEGER;
721                try {
722                    log.trace("fromNative(): integer type");
723                    int tsign = H5.H5Tget_sign(tid);
724                    datatypeSign = (tsign == HDF5Constants.H5T_SGN_NONE) ? SIGN_NONE : SIGN_2;
725                }
726                catch (Exception ex) {
727                    log.debug("fromNative(): int type failure: ", ex);
728                }
729            }
730            else if (nativeClass == HDF5Constants.H5T_FLOAT) {
731                datatypeClass = CLASS_FLOAT;
732                try {
733                    nativeFPebias = H5.H5Tget_ebias_long(tid);
734                }
735                catch (Exception ex) {
736                    log.debug("fromNative(): get_ebias failure: ", ex);
737                }
738                try {
739                    long[] fields = new long[5];
740                    H5.H5Tget_fields(tid, fields);
741                    nativeFPspos = fields[0];
742                    nativeFPepos = fields[1];
743                    nativeFPesize = fields[2];
744                    nativeFPmpos = fields[3];
745                    nativeFPmsize = fields[4];
746                }
747                catch (Exception ex) {
748                    log.debug("fromNative(): get_fields failure: ", ex);
749                }
750                try {
751                    nativeFPnorm = H5.H5Tget_norm(tid);
752                }
753                catch (Exception ex) {
754                    log.debug("fromNative(): get_norm failure: ", ex);
755                }
756                try {
757                    nativeFPinpad = H5.H5Tget_inpad(tid);
758                }
759                catch (Exception ex) {
760                    log.debug("fromNative(): get_inpad failure: ", ex);
761                }
762            }
763            else if (isChar) {
764                datatypeClass = CLASS_CHAR;
765                datatypeSign = (isUchar) ? SIGN_NONE : SIGN_2;
766                log.trace("fromNative(): CLASS_CHAR:datatypeSign={}", datatypeSign);
767            }
768            else if (nativeClass == HDF5Constants.H5T_STRING) {
769                datatypeClass = CLASS_STRING;
770                try {
771                    isVLEN = H5.H5Tdetect_class(tid, HDF5Constants.H5T_VLEN) || isVariableStr;
772                    log.trace("fromNative(): H5T_STRING:var str type={}", isVLEN);
773                    nativeStrPad = H5.H5Tget_strpad(tid);
774                }
775                catch (Exception ex) {
776                    log.debug("fromNative(): var str type failure: ", ex);
777                }
778                try {
779                    nativeStrCSET = H5.H5Tget_cset(tid);
780                }
781                catch (Exception ex) {
782                    log.debug("fromNative(): H5T_STRING:get_cset failure: ", ex);
783                }
784                log.trace("fromNative(): H5T_STRING:nativeStrPad={}, nativeStrCSET={}", nativeStrPad, nativeStrCSET);
785            }
786            else if (nativeClass == HDF5Constants.H5T_REFERENCE) {
787                datatypeClass = CLASS_REFERENCE;
788                log.trace("fromNative(): reference type");
789                try {
790                    isRegRef = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG);
791                }
792                catch (Exception ex) {
793                    log.debug("fromNative(): H5T_STD_REF_DSETREG: ", ex);
794                }
795                try {
796                    isRefObj = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_OBJ);
797                }
798                catch (Exception ex) {
799                    log.debug("fromNative(): H5T_STD_REF_OBJ: ", ex);
800                }
801            }
802            else if (nativeClass == HDF5Constants.H5T_ENUM) {
803                datatypeClass = CLASS_ENUM;
804                long tmptid = -1;
805                long basetid = -1;
806                try {
807                    log.trace("fromNative(): enum type");
808                    basetid = H5.H5Tget_super(tid);
809                    tmptid = basetid;
810                    basetid = H5.H5Tget_native_type(tmptid);
811                    log.trace("fromNative(): enum type basetid={}", basetid);
812                    if (basetid >= 0) {
813                        baseType = new H5Datatype(this.fileFormat, tmptid, this);
814                        datatypeSign = baseType.getDatatypeSign();
815                    }
816                }
817                catch (Exception ex) {
818                    log.debug("fromNative(): enum type failure: ", ex);
819                }
820                finally {
821                    close(tmptid);
822                    close(basetid);
823                }
824                try {
825                    int enumMemberCount = H5.H5Tget_nmembers(tid);
826                    String name = null;
827                    String enumStr = null;
828                    byte[] val = new byte[(int)tsize];
829                    enumMembers = new HashMap<>();
830                    for (int i = 0; i < enumMemberCount; i++) {
831                        name = H5.H5Tget_member_name(tid, i);
832                        H5.H5Tget_member_value(tid, i, val);
833                        switch ((int)H5.H5Tget_size(tid)) {
834                            case 1:
835                                enumStr = Byte.toString((HDFNativeData.byteToByte(val[0]))[0]);
836                                break;
837                            case 2:
838                                enumStr = Short.toString((HDFNativeData.byteToShort(val))[0]);
839                                break;
840                            case 4:
841                                enumStr = Integer.toString((HDFNativeData.byteToInt(val))[0]);
842                                break;
843                            case 8:
844                                enumStr = Long.toString((HDFNativeData.byteToLong(val))[0]);
845                                break;
846                            default:
847                                enumStr = "-1";
848                                break;
849                        }
850                        enumMembers.put(enumStr, name);
851                    }
852                }
853                catch (Exception ex) {
854                    log.debug("fromNative(): enum type failure: ", ex);
855                }
856            }
857            else if (nativeClass == HDF5Constants.H5T_VLEN) {
858                long tmptid = -1;
859                datatypeClass = CLASS_VLEN;
860                isVLEN = true;
861                try {
862                    log.trace("fromNative(): vlen type");
863                    tmptid = H5.H5Tget_super(tid);
864                    baseType = new H5Datatype(this.fileFormat, tmptid, this);
865                    if (baseType == null) {
866                        log.debug("fromNative(): VLEN datatype has null base type");
867                        throw new Exception("Datatype (VLEN) has no base datatype");
868                    }
869
870                    datatypeSign = baseType.getDatatypeSign();
871                }
872                catch (Exception ex) {
873                    log.debug("fromNative(): vlen type failure: ", ex);
874                }
875                finally {
876                    close(tmptid);
877                }
878            }
879            else if (nativeClass == HDF5Constants.H5T_BITFIELD) {
880                datatypeClass = CLASS_BITFIELD;
881            }
882            else if (nativeClass == HDF5Constants.H5T_OPAQUE) {
883                datatypeClass = CLASS_OPAQUE;
884
885                try {
886                    opaqueTag = H5.H5Tget_tag(tid);
887                }
888                catch (Exception ex) {
889                    log.debug("fromNative(): opaque type tag retrieval failed: ", ex);
890                    opaqueTag = null;
891                }
892            }
893            else {
894                log.debug("fromNative(): datatypeClass is unknown");
895            }
896
897            datatypeSize = (isVLEN && !isVariableStr) ? HDF5Constants.H5T_VL_T : tsize;
898        }
899        log.trace("fromNative(): datatypeClass={} baseType={} datatypeSize={}", datatypeClass, baseType, datatypeSize);
900    }
901
902    /**
903     * @param tid
904     *            the datatype identification disk.
905     *
906     * @return the memory datatype identifier if successful, and negative otherwise.
907     */
908    public static long toNative(long tid) {
909        // data type information
910        log.trace("toNative(): tid={} start", tid);
911        long nativeID = -1;
912
913        try {
914            nativeID = H5.H5Tget_native_type(tid);
915        }
916        catch (Exception ex) {
917            log.debug("toNative(): H5Tget_native_type(tid {}) failure: ", tid, ex);
918        }
919
920        try {
921            if (H5.H5Tis_variable_str(tid))
922                H5.H5Tset_size(nativeID, HDF5Constants.H5T_VARIABLE);
923        }
924        catch (Exception ex) {
925            log.debug("toNative(): var str type size failure: ", ex);
926        }
927
928        return nativeID;
929    }
930
931    /*
932     * (non-Javadoc)
933     *
934     * @see hdf.object.Datatype#createNative()
935     */
936    @SuppressWarnings("rawtypes")
937    @Override
938    public long createNative() {
939        long tid = -1;
940        long tmptid = -1;
941
942        String the_path = getFullName();
943        // isNamed == true should have non-null fileFormat
944        if (isNamed()) {
945            try {
946                tid = H5.H5Topen(getFID(), the_path, HDF5Constants.H5P_DEFAULT);
947            }
948            catch (Exception ex) {
949                log.debug("createNative(): name {} H5Topen failure: ", the_path, ex);
950            }
951        }
952        else
953            log.debug("createNative(): isNamed but named path={}", the_path);
954
955        if (tid >= 0) {
956            return tid;
957        }
958
959        log.trace("createNative(): datatypeClass={} datatypeSize={} baseType={}", datatypeClass, datatypeSize, baseType);
960
961        switch (datatypeClass) {
962            case CLASS_ARRAY:
963                try {
964                    if (baseType == null) {
965                        log.debug("createNative(): CLASS_ARRAY base type is NULL");
966                        break;
967                    }
968
969                    if ((tmptid = baseType.createNative()) < 0) {
970                        log.debug("createNative(): failed to create native datatype for ARRAY base datatype");
971                        break;
972                    }
973
974                    tid = H5.H5Tarray_create(tmptid, arrayDims.length, arrayDims);
975                }
976                catch (Exception ex) {
977                    log.debug("createNative(): native array datatype creation failed: ", ex);
978                    if (tid >= 0) close(tid);
979                    tid = -1;
980                }
981                finally {
982                    close(tmptid);
983                }
984
985                break;
986            case CLASS_COMPOUND:
987                try {
988                    tid = H5.H5Tcreate(CLASS_COMPOUND, datatypeSize);
989
990                    for (int i = 0; i < compoundMemberTypes.size(); i++) {
991                        H5Datatype memberType = null;
992                        String memberName = null;
993                        long memberOffset = -1;
994
995                        try {
996                            memberType = (H5Datatype) compoundMemberTypes.get(i);
997                        }
998                        catch (Exception ex) {
999                            log.debug("createNative(): get compound member[{}] type failure: ", i, ex);
1000                            memberType = null;
1001                        }
1002
1003                        try {
1004                            memberName = compoundMemberNames.get(i);
1005                        }
1006                        catch (Exception ex) {
1007                            log.debug("createNative(): get compound member[{}] name failure: ", i, ex);
1008                            memberName = null;
1009                        }
1010
1011                        try {
1012                            memberOffset = compoundMemberOffsets.get(i);
1013                        }
1014                        catch (Exception ex) {
1015                            log.debug("createNative(): get compound member[{}] offset failure: ", i, ex);
1016                            memberOffset = -1;
1017                        }
1018
1019                        long memberID = -1;
1020                        try {
1021                            memberID = memberType.createNative();
1022                            log.trace("createNative(): {} member[{}] with offset={} ID={}: ", memberName, i,
1023                                    memberOffset, memberID);
1024
1025                            H5.H5Tinsert(tid, memberName, memberOffset, memberID);
1026                        }
1027                        catch (Exception ex) {
1028                            log.debug("createNative(): compound type member[{}] insertion failure: ", i, ex);
1029                        }
1030                        finally {
1031                            close(memberID);
1032                        }
1033                    }
1034                }
1035                catch (Exception ex) {
1036                    log.debug("createNative(): native compound datatype creation failed: ", ex);
1037                    if (tid >= 0) close(tid);
1038                    tid = -1;
1039                }
1040                break;
1041            case CLASS_INTEGER:
1042                log.trace("createNative(): CLASS_INT of size {}", datatypeSize);
1043
1044                try {
1045                    switch ((int) datatypeSize) {
1046                        case 1:
1047                            log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT8");
1048                            tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8);
1049                            break;
1050                        case 2:
1051                            log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT16");
1052                            tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT16);
1053                            break;
1054                        case 4:
1055                            log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT32");
1056                            tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32);
1057                            break;
1058                        case 8:
1059                            log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT64");
1060                            tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT64);
1061                            break;
1062                        default:
1063                            if (datatypeSize == NATIVE) {
1064                                log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT");
1065                                tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT);
1066                            }
1067                            else {
1068                                /* Custom sized integer */
1069                                tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8);
1070                                H5.H5Tset_size(tid, datatypeSize);
1071                                H5.H5Tset_precision(tid, 8 * datatypeSize);
1072                            }
1073                            break;
1074                    }
1075
1076                    if (datatypeOrder == Datatype.ORDER_BE) {
1077                        log.trace("createNative(): CLASS_INT order is H5T_ORDER_BE");
1078                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
1079                    }
1080                    else if (datatypeOrder == Datatype.ORDER_LE) {
1081                        log.trace("createNative(): CLASS_INT order is H5T_ORDER_LE");
1082                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
1083                    }
1084
1085                    if (datatypeSign == Datatype.SIGN_NONE) {
1086                        log.trace("createNative(): CLASS_INT sign is H5T_SGN_NONE");
1087                        H5.H5Tset_sign(tid, HDF5Constants.H5T_SGN_NONE);
1088                    }
1089                }
1090                catch (Exception ex) {
1091                    log.debug("createNative(): native integer datatype creation failed: ", ex);
1092                    if (tid >= 0) close(tid);
1093                    tid = -1;
1094                }
1095
1096                break;
1097            case CLASS_ENUM:
1098                log.trace("createNative(): CLASS_ENUM");
1099                try {
1100                    if (baseType != null) {
1101                        if ((tmptid = baseType.createNative()) < 0) {
1102                            log.debug("createNative(): failed to create native type for ENUM base datatype");
1103                            break;
1104                        }
1105
1106                        tid = H5.H5Tenum_create(tmptid);
1107                    }
1108                    else {
1109                        if (datatypeSize == NATIVE)
1110                            datatypeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT);
1111
1112                        tid = H5.H5Tcreate(HDF5Constants.H5T_ENUM, datatypeSize);
1113                    }
1114
1115                    if (datatypeOrder == Datatype.ORDER_BE) {
1116                        log.trace("createNative(): CLASS_ENUM order is H5T_ORDER_BE");
1117                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
1118                    }
1119                    else if (datatypeOrder == Datatype.ORDER_LE) {
1120                        log.trace("createNative(): CLASS_ENUM order is H5T_ORDER_LE");
1121                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
1122                    }
1123
1124                    if (datatypeSign == Datatype.SIGN_NONE) {
1125                        log.trace("createNative(): CLASS_ENUM sign is H5T_SGN_NONE");
1126                        H5.H5Tset_sign(tid, HDF5Constants.H5T_SGN_NONE);
1127                    }
1128                }
1129                catch (Exception ex) {
1130                    log.debug("createNative(): native enum datatype creation failed: ", ex);
1131                    if (tid >= 0) close(tid);
1132                    tid = -1;
1133                }
1134                finally {
1135                    close(tmptid);
1136                }
1137
1138                break;
1139            case CLASS_FLOAT:
1140                try {
1141                    tid = H5.H5Tcopy((datatypeSize == 8) ? HDF5Constants.H5T_NATIVE_DOUBLE : HDF5Constants.H5T_NATIVE_FLOAT);
1142
1143                    if (datatypeOrder == Datatype.ORDER_BE) {
1144                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
1145                    }
1146                    else if (datatypeOrder == Datatype.ORDER_LE) {
1147                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
1148                    }
1149
1150                    if (nativeFPebias > 0) {
1151                        H5.H5Tset_ebias(tid, nativeFPebias);
1152                    }
1153
1154                    if (nativeFPnorm >= 0) {
1155                        H5.H5Tset_norm(tid, nativeFPnorm);
1156                    }
1157
1158                    if (nativeFPinpad >= 0) {
1159                        H5.H5Tset_inpad(tid, nativeFPinpad);
1160                    }
1161
1162                    if ((nativeFPesize >= 0) && (nativeFPmsize >= 0)) {
1163                        H5.H5Tset_fields(tid, nativeFPspos, nativeFPmpos, nativeFPesize, nativeFPmpos, nativeFPmsize);
1164                    }
1165                }
1166                catch (Exception ex) {
1167                    log.debug("createNative(): native floating-point datatype creation failed: ", ex);
1168                    if (tid >= 0) close(tid);
1169                    tid = -1;
1170                }
1171
1172                break;
1173            case CLASS_CHAR:
1174                try {
1175                    tid = H5.H5Tcopy((datatypeSign == Datatype.SIGN_NONE) ? HDF5Constants.H5T_NATIVE_UCHAR
1176                            : HDF5Constants.H5T_NATIVE_CHAR);
1177                }
1178                catch (Exception ex) {
1179                    log.debug("createNative(): native character datatype creation failed: ", ex);
1180                    if (tid >= 0) close(tid);
1181                    tid = -1;
1182                }
1183
1184                break;
1185            case CLASS_STRING:
1186                try {
1187                    tid = H5.H5Tcopy(HDF5Constants.H5T_C_S1);
1188
1189                    H5.H5Tset_size(tid, (isVLEN || datatypeSize < 0) ? HDF5Constants.H5T_VARIABLE : datatypeSize);
1190
1191                    log.trace("createNative(): isVlenStr={} nativeStrPad={} nativeStrCSET={}", isVLEN, nativeStrPad,
1192                            nativeStrCSET);
1193
1194                    H5.H5Tset_strpad(tid, (nativeStrPad >= 0) ? nativeStrPad : HDF5Constants.H5T_STR_NULLTERM);
1195
1196                    if (nativeStrCSET >= 0) {
1197                        H5.H5Tset_cset(tid, nativeStrCSET);
1198                    }
1199                }
1200                catch (Exception ex) {
1201                    log.debug("createNative(): native string datatype creation failed: ", ex);
1202                    if (tid >= 0) close(tid);
1203                    tid = -1;
1204                }
1205
1206                break;
1207            case CLASS_REFERENCE:
1208                try {
1209                    long objRefTypeSize = H5.H5Tget_size(HDF5Constants.H5T_STD_REF_OBJ);
1210
1211                    tid = H5.H5Tcopy((datatypeSize > objRefTypeSize) ? HDF5Constants.H5T_STD_REF_DSETREG
1212                            : HDF5Constants.H5T_STD_REF_OBJ);
1213                }
1214                catch (Exception ex) {
1215                    log.debug("createNative(): native reference datatype creation failed: ", ex);
1216                    if (tid >= 0) close(tid);
1217                    tid = -1;
1218                }
1219
1220                break;
1221            case CLASS_VLEN:
1222                try {
1223                    if (baseType == null) {
1224                        log.debug("createNative(): CLASS_VLEN base type is NULL");
1225                        break;
1226                    }
1227
1228                    if ((tmptid = baseType.createNative()) < 0) {
1229                        log.debug("createNative(): failed to create native datatype for VLEN base datatype");
1230                        break;
1231                    }
1232
1233                    tid = H5.H5Tvlen_create(tmptid);
1234                }
1235                catch (Exception ex) {
1236                    log.debug("createNative(): native variable-length datatype creation failed: ", ex);
1237                    if (tid >= 0) close(tid);
1238                    tid = -1;
1239                }
1240                finally {
1241                    close(tmptid);
1242                }
1243
1244                break;
1245            case CLASS_BITFIELD:
1246                log.trace("createNative(): CLASS_BITFIELD size is {}", datatypeSize);
1247
1248                try {
1249                    switch ((int) datatypeSize) {
1250                        case 1:
1251                            log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B8");
1252                            tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B8);
1253                            break;
1254                        case 2:
1255                            log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B16");
1256                            tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B16);
1257                            break;
1258                        case 4:
1259                            log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B32");
1260                            tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B32);
1261                            break;
1262                        case 8:
1263                            log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B64");
1264                            tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B64);
1265                            break;
1266                        default:
1267                            if (datatypeSize == NATIVE)
1268                                datatypeSize = 1;
1269
1270                            /* Custom sized bitfield */
1271                            tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B8);
1272                            H5.H5Tset_size(tid, datatypeSize);
1273                            H5.H5Tset_precision(tid, 8 * datatypeSize);
1274
1275                            break;
1276                    }
1277
1278                    if (datatypeOrder == Datatype.ORDER_BE) {
1279                        log.trace("createNative(): CLASS_BITFIELD order is H5T_ORDER_BE");
1280                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
1281                    }
1282                    else if (datatypeOrder == Datatype.ORDER_LE) {
1283                        log.trace("createNative(): CLASS_BITFIELD order is H5T_ORDER_LE");
1284                        H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
1285                    }
1286                }
1287                catch (Exception ex) {
1288                    log.debug("createNative(): native bitfield datatype creation failed: ", ex);
1289                    if (tid >= 0) close(tid);
1290                    tid = -1;
1291                }
1292
1293                break;
1294            case CLASS_OPAQUE:
1295                log.trace("createNative(): CLASS_OPAQUE is {}-byte H5T_OPAQUE", datatypeSize);
1296
1297                try {
1298                    if (datatypeSize == NATIVE)
1299                        tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_OPAQUE);
1300                    else
1301                        tid = H5.H5Tcreate(HDF5Constants.H5T_OPAQUE, datatypeSize);
1302
1303                    if (opaqueTag != null) {
1304                        H5.H5Tset_tag(tid, opaqueTag);
1305                    }
1306                }
1307                catch (Exception ex) {
1308                    log.debug("createNative(): native opaque datatype creation failed: ", ex);
1309                    if (tid >= 0) close(tid);
1310                    tid = -1;
1311                }
1312
1313                break;
1314            default:
1315                log.debug("createNative(): Unknown class");
1316                break;
1317        } // (tclass)
1318
1319        // set up enum members
1320        if ((datatypeClass == CLASS_ENUM) && (enumMembers != null)) {
1321            log.trace("createNative(): set up enum members");
1322            try {
1323                String memstr;
1324                String memname;
1325                byte[] memval = null;
1326
1327                Iterator entries = enumMembers.entrySet().iterator();
1328                while (entries.hasNext()) {
1329                    Entry thisEntry = (Entry) entries.next();
1330                    memstr = (String) thisEntry.getKey();
1331                    memname = (String) thisEntry.getValue();
1332
1333                    if (datatypeSize == 1) {
1334                        log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT8");
1335                        Byte tval = Byte.parseByte(memstr);
1336                        memval = HDFNativeData.byteToByte(tval);
1337                    }
1338                    else if (datatypeSize == 2) {
1339                        log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT16");
1340                        Short tval = Short.parseShort(memstr);
1341                        memval = HDFNativeData.shortToByte(tval);
1342                    }
1343                    else if (datatypeSize == 4) {
1344                        log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT32");
1345                        Integer tval = Integer.parseInt(memstr);
1346                        memval = HDFNativeData.intToByte(tval);
1347                    }
1348                    else if (datatypeSize == 8) {
1349                        log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT64");
1350                        Long tval = Long.parseLong(memstr);
1351                        memval = HDFNativeData.longToByte(tval);
1352                    }
1353                    else {
1354                        log.debug("createNative(): enum datatypeSize incorrect");
1355                    }
1356                    log.trace("createNative(): H5Tenum_insert {} {}", memname, memval);
1357                    H5.H5Tenum_insert(tid, memname, memval);
1358                }
1359            }
1360            catch (Exception ex) {
1361                log.debug("createNative(): set up enum members failure: ", ex);
1362            }
1363        } // (datatypeClass == CLASS_ENUM)
1364
1365        try {
1366            tmptid = tid;
1367            tid = H5.H5Tget_native_type(tmptid);
1368        }
1369        catch (HDF5Exception ex) {
1370            log.debug("createNative(): H5Tget_native_type({}) failure: ", tmptid, ex);
1371        }
1372        finally {
1373            close(tmptid);
1374        }
1375
1376        return tid;
1377    }
1378
1379    /**
1380     * Allocates a one-dimensional array of byte, short, int, long, float, double,
1381     * or String to store data in memory.
1382     *
1383     * For example,
1384     *
1385     * <pre>
1386     * long tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32);
1387     * int[] data = (int[]) H5Datatype.allocateArray(datatype, 100);
1388     * </pre>
1389     *
1390     * returns a 32-bit integer array of size 100.
1391     *
1392     * @param dtype
1393     *            the type.
1394     * @param nPoints
1395     *            the total number of data points of the array.
1396     *
1397     * @return the array object if successful; otherwise, return null.
1398     *
1399     * @throws OutOfMemoryError
1400     *             If there is a failure.
1401     */
1402    public static final Object allocateArray(final H5Datatype dtype, int nPoints) throws OutOfMemoryError {
1403        log.trace("allocateArray(): start: nPoints={}", nPoints);
1404
1405        Object data = null;
1406        H5Datatype baseType = (H5Datatype) dtype.getDatatypeBase();
1407        int typeClass = dtype.getDatatypeClass();
1408        long typeSize = dtype.getDatatypeSize();
1409
1410        if (nPoints < 0) {
1411            log.debug("allocateArray(): nPoints < 0");
1412            return null;
1413        }
1414
1415        // Scalar members have dimensionality zero, i.e. size =0
1416        // what can we do about it, set the size to 1
1417        if (nPoints == 0) {
1418            nPoints = 1;
1419        }
1420
1421        log.trace("allocateArray(): tclass={} : tsize={}", typeClass, typeSize);
1422
1423        if (dtype.isVarStr() || dtype.isVLEN() || dtype.isRegRef()) {
1424            log.trace("allocateArray(): is_variable_str={} || isVL={} || is_reg_ref={}", dtype.isVarStr(), dtype.isVLEN(), dtype.isRegRef());
1425
1426            data = new String[nPoints];
1427            for (int i = 0; i < nPoints; i++) {
1428                ((String[]) data)[i] = "";
1429            }
1430        }
1431        else if (typeClass == HDF5Constants.H5T_INTEGER) {
1432            log.trace("allocateArray(): class H5T_INTEGER");
1433
1434            switch ((int) typeSize) {
1435                case 1:
1436                    data = new byte[nPoints];
1437                    break;
1438                case 2:
1439                    data = new short[nPoints];
1440                    break;
1441                case 4:
1442                    data = new int[nPoints];
1443                    break;
1444                case 8:
1445                    data = new long[nPoints];
1446                    break;
1447                default:
1448                    break;
1449            }
1450        }
1451        else if (typeClass == HDF5Constants.H5T_ENUM) {
1452            log.trace("allocateArray(): class H5T_ENUM");
1453
1454            if (baseType != null)
1455                data = H5Datatype.allocateArray(baseType, nPoints);
1456            else
1457                data = new byte[(int) (nPoints * typeSize)];
1458        }
1459        else if (typeClass == HDF5Constants.H5T_COMPOUND) {
1460            log.trace("allocateArray(): class H5T_COMPOUND");
1461
1462            data = new ArrayList<>(dtype.getCompoundMemberTypes().size());
1463        }
1464        else if (typeClass == HDF5Constants.H5T_FLOAT) {
1465            log.trace("allocateArray(): class H5T_FLOAT");
1466
1467            switch ((int) typeSize) {
1468                case 4:
1469                    data = new float[nPoints];
1470                    break;
1471                case 8:
1472                    data = new double[nPoints];
1473                    break;
1474                default:
1475                    break;
1476            }
1477        }
1478        else if ((typeClass == HDF5Constants.H5T_STRING) || (typeClass == HDF5Constants.H5T_REFERENCE)) {
1479            log.trace("allocateArray(): class H5T_STRING || H5T_REFERENCE");
1480
1481            data = new byte[(int) (nPoints * typeSize)];
1482        }
1483        else if (typeClass == HDF5Constants.H5T_ARRAY) {
1484            log.trace("allocateArray(): class H5T_ARRAY");
1485
1486            try {
1487                log.trace("allocateArray(): ArrayRank={}", dtype.getArrayDims().length);
1488
1489                // Use the base datatype to define the array
1490                long[] arrayDims = dtype.getArrayDims();
1491                int asize = nPoints;
1492                for (int j = 0; j < arrayDims.length; j++) {
1493                    log.trace("allocateArray(): Array dims[{}]={}", j, arrayDims[j]);
1494
1495                    asize *= arrayDims[j];
1496                }
1497
1498                if (baseType != null) {
1499                    data = H5Datatype.allocateArray(baseType, asize);
1500                }
1501            }
1502            catch (Exception ex) {
1503                log.debug("allocateArray(): H5T_ARRAY class failure: ", ex);
1504            }
1505        }
1506        else if ((typeClass == HDF5Constants.H5T_OPAQUE) || (typeClass == HDF5Constants.H5T_BITFIELD)) {
1507            log.trace("allocateArray(): class H5T_OPAQUE || H5T_BITFIELD");
1508
1509            data = new byte[(int) (nPoints * typeSize)];
1510        }
1511        else {
1512            log.debug("allocateArray(): class ???? ({})", typeClass);
1513
1514            data = null;
1515        }
1516
1517        return data;
1518    }
1519
1520    /**
1521     * Returns the size (in bytes) of a given datatype identifier.
1522     * <p>
1523     * It basically just calls H5Tget_size(tid).
1524     *
1525     * @param tid
1526     *            The datatype identifier.
1527     *
1528     * @return The size of the datatype in bytes.
1529     *
1530     * @see hdf.hdf5lib.H5#H5Tget_size(long)
1531     */
1532    public static final long getDatatypeSize(long tid) {
1533        // data type information
1534        long tsize = -1;
1535
1536        try {
1537            tsize = H5.H5Tget_size(tid);
1538        }
1539        catch (Exception ex) {
1540            tsize = -1;
1541        }
1542
1543        return tsize;
1544    }
1545
1546    /*
1547     * (non-Javadoc)
1548     *
1549     * @see hdf.object.Datatype#getDescription()
1550     */
1551    @Override
1552    public String getDescription() {
1553        log.trace("getDescription(): start - isNamed={}", isNamed());
1554
1555        if (datatypeDescription != null) {
1556            return datatypeDescription;
1557        }
1558
1559        StringBuilder description = new StringBuilder();
1560        long tid = -1;
1561
1562        switch (datatypeClass) {
1563            case CLASS_CHAR:
1564                log.trace("getDescription(): Char");
1565                description.append("8-bit ").append(isUnsigned() ? "unsigned " : "").append("integer");
1566                break;
1567            case CLASS_INTEGER:
1568                log.trace("getDescription(): Int");
1569                if (datatypeSize == NATIVE)
1570                    description.append("native ").append(isUnsigned() ? "unsigned " : "").append("integer");
1571                else
1572                    description.append(String.valueOf(datatypeSize * 8)).append("-bit ").append(isUnsigned() ? "unsigned " : "").append("integer");
1573                break;
1574            case CLASS_FLOAT:
1575                log.trace("getDescription(): Float");
1576                if (datatypeSize == NATIVE)
1577                    description.append("native floating-point");
1578                else
1579                    description.append(String.valueOf(datatypeSize * 8)).append("-bit floating-point");
1580                break;
1581            case CLASS_STRING:
1582                log.trace("getDescription(): String");
1583                description.append("String, length = ").append(isVarStr() ? "variable" : datatypeSize);
1584
1585                try {
1586                    tid = createNative();
1587                    if (tid >= 0) {
1588                        String strPadType;
1589                        String strCSETType;
1590                        int strPad = H5.H5Tget_strpad(tid);
1591                        int strCSET = H5.H5Tget_cset(tid);
1592
1593                        if (strPad == HDF5Constants.H5T_STR_NULLTERM)
1594                            strPadType = "H5T_STR_NULLTERM";
1595                        else if (strPad == HDF5Constants.H5T_STR_NULLPAD)
1596                            strPadType = "H5T_STR_NULLPAD";
1597                        else if (strPad == HDF5Constants.H5T_STR_SPACEPAD)
1598                            strPadType = "H5T_STR_SPACEPAD";
1599                        else
1600                            strPadType = null;
1601
1602                        if (strPadType != null)
1603                            description.append(", padding = ").append(strPadType);
1604
1605                        if (strCSET == HDF5Constants.H5T_CSET_ASCII)
1606                            strCSETType = "H5T_CSET_ASCII";
1607                        else if (strCSET == HDF5Constants.H5T_CSET_UTF8)
1608                            strCSETType = "H5T_CSET_UTF8";
1609                        else
1610                            strCSETType = null;
1611
1612                        if (strCSETType != null)
1613                            description.append(", cset = ").append(strCSETType);
1614                    }
1615                    else {
1616                        log.debug("createNative() failure");
1617                    }
1618                }
1619                catch (Exception ex) {
1620                    log.debug("H5Tget_strpad failure: ", ex);
1621                }
1622                finally {
1623                    close(tid);
1624                }
1625                break;
1626            case CLASS_BITFIELD:
1627                log.trace("getDescription(): Bit");
1628                if (datatypeSize == NATIVE)
1629                    description.append("native bitfield");
1630                else
1631                    description.append(String.valueOf(datatypeSize * 8)).append("-bit bitfield");
1632                break;
1633            case CLASS_OPAQUE:
1634                log.trace("getDescription(): Opaque");
1635                if (datatypeSize == NATIVE)
1636                    description.append("native Opaque");
1637                else
1638                    description.append(String.valueOf(datatypeSize)).append("-byte Opaque");
1639
1640                if (opaqueTag != null) {
1641                    description.append(", tag = ").append(opaqueTag);
1642                }
1643
1644                break;
1645            case CLASS_COMPOUND:
1646                log.trace("getDescription(): Compound");
1647                description.append("Compound");
1648
1649                if ((compoundMemberTypes != null) && !compoundMemberTypes.isEmpty()) {
1650                    Iterator<String> memberNames = null;
1651                    Iterator<Datatype> memberTypes = compoundMemberTypes.iterator();
1652
1653                    if (compoundMemberNames != null)
1654                        memberNames = compoundMemberNames.iterator();
1655
1656                    description.append(" {");
1657
1658                    while (memberTypes.hasNext()) {
1659                        if (memberNames != null && memberNames.hasNext()) {
1660                            description.append(memberNames.next()).append(" = ");
1661                        }
1662
1663                        description.append(memberTypes.next().getDescription());
1664
1665                        if (memberTypes.hasNext())
1666                            description.append(", ");
1667                    }
1668
1669                    description.append("}");
1670                }
1671
1672                break;
1673            case CLASS_REFERENCE:
1674                log.trace("getDescription(): Ref");
1675                description.append("Reference");
1676
1677                try {
1678                    boolean isRegionType = false;
1679
1680                    tid = createNative();
1681                    if (tid >= 0) {
1682                        isRegionType = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG);
1683
1684                        description.setLength(0);
1685                        if (isRegionType) {
1686                            description.append("Dataset region reference");
1687                        }
1688                        else {
1689                            description.append("Object reference");
1690                        }
1691                    }
1692                }
1693                catch (Exception ex) {
1694                    log.debug("H5.H5Tequal failure: ", ex);
1695                }
1696                finally {
1697                    close(tid);
1698                }
1699
1700                break;
1701            case CLASS_ENUM:
1702                log.trace("getDescription(): Enum");
1703                if (datatypeSize == NATIVE)
1704                    description.append("native enum");
1705                else
1706                    description.append(String.valueOf(datatypeSize * 8)).append("-bit enum");
1707
1708                String members = getEnumMembersAsString();
1709                if (members != null)
1710                    description.append(" (").append(members).append(")");
1711
1712                break;
1713            case CLASS_VLEN:
1714                log.trace("getDescription(): Var Len");
1715                description.append("Variable-length");
1716
1717                if (baseType != null) {
1718                    description.append(" of ").append(baseType.getDescription());
1719                }
1720
1721                break;
1722            case CLASS_ARRAY:
1723                log.trace("getDescription(): Array");
1724                description.append("Array");
1725
1726                if (arrayDims != null) {
1727                    description.append(" [");
1728                    for (int i = 0; i < arrayDims.length; i++) {
1729                        description.append(arrayDims[i]);
1730                        if (i < arrayDims.length - 1)
1731                            description.append(" x ");
1732                    }
1733                    description.append("]");
1734                }
1735
1736                if (baseType != null) {
1737                    description.append(" of ").append(baseType.getDescription());
1738                }
1739
1740                break;
1741            default:
1742                description.append("Unknown");
1743                break;
1744        }
1745        if (isNamed())
1746            description.append("->").append(getFullName());
1747
1748        return description.toString();
1749    }
1750
1751    /**
1752     * Checks if a datatype specified by the identifier is an unsigned integer.
1753     *
1754     * @param tid
1755     *            the datatype ID to be checked.
1756     *
1757     * @return true is the datatype is an unsigned integer; otherwise returns false.
1758     */
1759    public static final boolean isUnsigned(long tid) {
1760        boolean unsigned = false;
1761
1762        if (tid >= 0) {
1763            try {
1764                int tclass = H5.H5Tget_class(tid);
1765                log.trace("isUnsigned(): tclass = {}", tclass);
1766                if (tclass != HDF5Constants.H5T_FLOAT && tclass != HDF5Constants.H5T_STRING
1767                        && tclass != HDF5Constants.H5T_REFERENCE && tclass != HDF5Constants.H5T_BITFIELD
1768                        && tclass != HDF5Constants.H5T_OPAQUE && tclass != HDF5Constants.H5T_VLEN
1769                        && tclass != HDF5Constants.H5T_COMPOUND && tclass != HDF5Constants.H5T_ARRAY) {
1770                    int tsign = H5.H5Tget_sign(tid);
1771                    if (tsign == HDF5Constants.H5T_SGN_NONE) {
1772                        unsigned = true;
1773                    }
1774                    else {
1775                        log.trace("isUnsigned(): not unsigned");
1776                    }
1777                }
1778                else {
1779                    log.trace("isUnsigned(): tclass not integer type");
1780                }
1781            }
1782            catch (Exception ex) {
1783                log.debug("isUnsigned(): Datatype {} failure", tid, ex);
1784                unsigned = false;
1785            }
1786        }
1787        else {
1788            log.trace("isUnsigned(): not a valid datatype");
1789        }
1790
1791        return unsigned;
1792    }
1793
1794    /*
1795     * (non-Javadoc)
1796     *
1797     * @see hdf.object.Datatype#getMetadata()
1798     */
1799    @Override
1800    public List<Attribute> getMetadata() throws HDF5Exception {
1801        return this.getMetadata(fileFormat.getIndexType(null), fileFormat.getIndexOrder(null));
1802    }
1803
1804    /*
1805     * (non-Javadoc)
1806     *
1807     * @see hdf.object.DataFormat#getMetadata(int...)
1808     */
1809    public List<Attribute> getMetadata(int... attrPropList) throws HDF5Exception {
1810        // load attributes first
1811        if (attributeList == null) {
1812            int indxType = fileFormat.getIndexType(null);
1813            int order = fileFormat.getIndexOrder(null);
1814
1815            if (attrPropList.length > 0) {
1816                indxType = attrPropList[0];
1817                if (attrPropList.length > 1) {
1818                    order = attrPropList[1];
1819                }
1820            }
1821
1822            try {
1823                attributeList = H5File.getAttribute(this, indxType, order);
1824            }
1825            catch (Exception ex) {
1826                log.debug("getMetadata(): H5File.getAttribute failure: ", ex);
1827            }
1828        } //  (attributeList == null)
1829
1830        try {
1831            this.linkTargetObjName = H5File.getLinkTargetName(this);
1832        }
1833        catch (Exception ex) {
1834            log.debug("getMetadata(): H5File.linkTargetObjName failure: ", ex);
1835        }
1836
1837        return attributeList;
1838    }
1839
1840    /*
1841     * (non-Javadoc)
1842     *
1843     * @see hdf.object.Datatype#writeMetadata(java.lang.Object)
1844     */
1845    @Override
1846    public void writeMetadata(Object info) throws Exception {
1847
1848        // only attribute metadata is supported.
1849        if (!(info instanceof Attribute)) {
1850            log.debug("writeMetadata(): Object not an Attribute");
1851            return;
1852        }
1853
1854        boolean attrExisted = false;
1855        Attribute attr = (Attribute) info;
1856
1857        if (attributeList == null) {
1858            this.getMetadata();
1859        }
1860
1861        if (attributeList != null)
1862            attrExisted = attributeList.contains(attr);
1863
1864        getFileFormat().writeAttribute(this, attr, attrExisted);
1865
1866        // add the new attribute into attribute list
1867        if (!attrExisted) {
1868            attributeList.add(attr);
1869            nAttributes = attributeList.size();
1870        }
1871    }
1872
1873    /*
1874     * (non-Javadoc)
1875     *
1876     * @see hdf.object.Datatype#removeMetadata(java.lang.Object)
1877     */
1878    @Override
1879    public void removeMetadata(Object info) throws HDF5Exception {
1880        // only attribute metadata is supported.
1881        if (!(info instanceof Attribute)) {
1882            log.debug("removeMetadata(): Object not an attribute");
1883            return;
1884        }
1885
1886        Attribute attr = (Attribute) info;
1887        long tid = open();
1888        try {
1889            H5.H5Adelete(tid, attr.getName());
1890            List<Attribute> attrList = getMetadata();
1891            attrList.remove(attr);
1892            nAttributes = attributeList.size();
1893        }
1894        catch (Exception ex) {
1895            log.debug("removeMetadata(): ", ex);
1896        }
1897        finally {
1898            close(tid);
1899        }
1900    }
1901
1902    @Override
1903    public void setName(String newName) throws Exception {
1904        if (newName == null)
1905            throw new IllegalArgumentException("The new name is NULL");
1906
1907        H5File.renameObject(this, newName);
1908        super.setName(newName);
1909    }
1910    @Override
1911    public void setFullname(String newPath, String newName) throws Exception {
1912        H5File.renameObject(this, newPath, newName);
1913        super.setFullname(newPath, newName);
1914    }
1915
1916    @Override
1917    public boolean isText() {
1918        return (datatypeClass == Datatype.CLASS_STRING);
1919    }
1920
1921    public boolean isRefObj() {
1922        return isRefObj;
1923    }
1924
1925    public boolean isRegRef() {
1926        return isRegRef;
1927    }
1928
1929    public int getNativeStrPad() {
1930        return nativeStrPad;
1931    }
1932
1933    /**
1934     * Extracts compound information into flat structure.
1935     * <p>
1936     * For example, compound datatype "nest" has {nest1{a, b, c}, d, e} then extractCompoundInfo() will
1937     * put the names of nested compound fields into a flat list as
1938     *
1939     * <pre>
1940     * nest.nest1.a
1941     * nest.nest1.b
1942     * nest.nest1.c
1943     * nest.d
1944     * nest.e
1945     * </pre>
1946     *
1947     *@param dtype
1948     *            the datatype to extract compound info from
1949     * @param name
1950     *            the name of the compound datatype
1951     * @param names
1952     *            the list to store the member names of the compound datatype
1953     * @param flatListTypes
1954     *            the list to store the nested member names of the compound datatype
1955     */
1956    public static void extractCompoundInfo(final H5Datatype dtype, String name, List<String> names, List<Datatype> flatListTypes) {
1957        log.trace("extractCompoundInfo(): start: name={}", name);
1958
1959        if (dtype.isArray()) {
1960            log.trace("extractCompoundInfo(): array type - extracting compound info from base datatype");
1961            H5Datatype.extractCompoundInfo((H5Datatype) dtype.getDatatypeBase(), name, names, flatListTypes);
1962        }
1963        else if (dtype.isVLEN() && !dtype.isVarStr()) {
1964            log.trace("extractCompoundInfo(): variable-length type - extracting compound info from base datatype");
1965            H5Datatype.extractCompoundInfo((H5Datatype) dtype.getDatatypeBase(), name, names, flatListTypes);
1966        }
1967        else if (dtype.isCompound()) {
1968            List<String> compoundMemberNames = dtype.getCompoundMemberNames();
1969            List<Datatype> compoundMemberTypes = dtype.getCompoundMemberTypes();
1970            Datatype mtype = null;
1971            String mname = null;
1972
1973            if (compoundMemberNames == null) {
1974                log.debug("extractCompoundInfo(): compoundMemberNames is null");
1975                return;
1976            }
1977
1978            if (compoundMemberNames.isEmpty()) {
1979                log.debug("extractCompoundInfo(): compound datatype has no members");
1980                return;
1981            }
1982
1983            log.trace("extractCompoundInfo(): nMembers={}", compoundMemberNames.size());
1984
1985            for (int i = 0; i < compoundMemberNames.size(); i++) {
1986                log.trace("extractCompoundInfo(): member[{}]:", i);
1987
1988                mtype = compoundMemberTypes.get(i);
1989
1990                log.trace("extractCompoundInfo(): type={} with size={}", mtype.getDescription(), mtype.getDatatypeSize());
1991
1992                if (names != null) {
1993                    mname = name + compoundMemberNames.get(i);
1994                    log.trace("extractCompoundInfo(): mname={}, name={}", mname, name);
1995                }
1996
1997                if (mtype.isCompound()) {
1998                    H5Datatype.extractCompoundInfo((H5Datatype) mtype, mname + CompoundDS.SEPARATOR, names, flatListTypes);
1999                    log.trace("extractCompoundInfo(): continue after recursive compound");
2000                    continue;
2001                }
2002
2003                if (names != null) {
2004                    names.add(mname);
2005                }
2006
2007                flatListTypes.add(mtype);
2008
2009                /*
2010                 * For ARRAY of COMPOUND and VLEN of COMPOUND types, we first add the top-level
2011                 * array or vlen type to the list of datatypes, and then follow that with a
2012                 * listing of the datatypes inside the nested compound.
2013                 */
2014                /*
2015                 * TODO: Don't flatten variable-length types until true variable-length support
2016                 * is implemented.
2017                 */
2018                if (mtype.isArray() /* || (mtype.isVLEN() && !mtype.isVarStr()) */) {
2019                    H5Datatype.extractCompoundInfo((H5Datatype) mtype, mname + CompoundDS.SEPARATOR, names, flatListTypes);
2020                }
2021            }
2022        }
2023    }
2024
2025    /**
2026     * Creates a datatype of a compound with one field.
2027     * <p>
2028     * This function is needed to read/write data field by field.
2029     *
2030     * @param memberName
2031     *            The name of the datatype
2032     *
2033     * @return the identifier of the compound datatype.
2034     *
2035     * @throws HDF5Exception
2036     *             If there is an error at the HDF5 library level.
2037     */
2038    public long createCompoundFieldType(String memberName) throws HDF5Exception {
2039        log.trace("createCompoundFieldType(): start member_name={}", memberName);
2040
2041        long topTID = -1;
2042        long tmpTID1 = -1;
2043
2044        try {
2045            if (this.isArray()) {
2046                log.trace("createCompoundFieldType(): array datatype");
2047
2048                if (baseType != null) {
2049                    log.trace("createCompoundFieldType(): creating compound field type from base datatype");
2050                    tmpTID1 = ((H5Datatype) baseType).createCompoundFieldType(memberName);
2051                }
2052
2053                log.trace("createCompoundFieldType(): creating container array datatype");
2054                topTID = H5.H5Tarray_create(tmpTID1, arrayDims.length, arrayDims);
2055            }
2056            else if (this.isVLEN()) {
2057                log.trace("createCompoundFieldType(): variable-length datatype");
2058
2059                if (baseType != null) {
2060                    log.trace("createCompoundFieldType(): creating compound field type from base datatype");
2061                    tmpTID1 = ((H5Datatype) baseType).createCompoundFieldType(memberName);
2062                }
2063
2064                log.trace("createCompoundFieldType(): creating container variable-length datatype");
2065                topTID = H5.H5Tvlen_create(tmpTID1);
2066            }
2067            else if (this.isCompound()) {
2068                log.trace("createCompoundFieldType(): compound datatype");
2069
2070                String insertedName = memberName;
2071
2072                int sep = memberName.indexOf(CompoundDS.SEPARATOR);
2073                if (sep >= 0) {
2074                    /*
2075                     * If a compound separator character is present in the supplied string, then
2076                     * there is an additional level of compound nesting. We will create a compound
2077                     * type to hold the nested compound type.
2078                     */
2079                    insertedName = memberName.substring(0, sep);
2080
2081                    log.trace("createCompoundFieldType(): member with name {} is nested inside compound", insertedName);
2082                }
2083
2084                /*
2085                 * Retrieve the index of the compound member by its name.
2086                 */
2087                int memberIndex = this.compoundMemberNames.indexOf(insertedName);
2088                if (memberIndex >= 0) {
2089                    H5Datatype memberType = (H5Datatype) this.compoundMemberTypes.get(memberIndex);
2090
2091                    log.trace("createCompoundFieldType(): Member {} is type {} of size={} with baseType={}", insertedName,
2092                            memberType.getDescription(), memberType.getDatatypeSize(), memberType.getDatatypeBase());
2093
2094                    if (sep >= 0)
2095                        /*
2096                         * Additional compound nesting; create the nested compound type.
2097                         */
2098                        tmpTID1 = memberType.createCompoundFieldType(memberName.substring(sep + 1));
2099                    else
2100                        tmpTID1 = memberType.createNative();
2101
2102                    log.trace("createCompoundFieldType(): creating container compound datatype");
2103                    topTID = H5.H5Tcreate(HDF5Constants.H5T_COMPOUND, datatypeSize);
2104
2105                    log.trace("createCompoundFieldType(): inserting member {} into compound datatype", insertedName);
2106                    H5.H5Tinsert(topTID, insertedName, 0, tmpTID1);
2107
2108                    /*
2109                     * WARNING!!! This step is crucial. Without it, the compound type created might be larger than
2110                     * the size of the single datatype field we are inserting. Performing a read with a compound
2111                     * datatype of an incorrect size will corrupt JVM memory and cause strange behavior and crashes.
2112                     */
2113                    H5.H5Tpack(topTID);
2114                }
2115                else {
2116                    log.debug("createCompoundFieldType(): member name {} not found in compound datatype's member name list", memberName);
2117                }
2118            }
2119        }
2120        catch (Exception ex) {
2121            log.debug("createCompoundFieldType(): creation of compound field type failed: ", ex);
2122            topTID = -1;
2123        }
2124        finally {
2125            close(tmpTID1);
2126        }
2127
2128        return topTID;
2129    }
2130
2131    private boolean datatypeIsComplex(long tid) {
2132        long tclass = HDF5Constants.H5T_NO_CLASS;
2133
2134        try {
2135            tclass = H5.H5Tget_class(tid);
2136        }
2137        catch (Exception ex) {
2138            log.debug("datatypeIsComplex():", ex);
2139        }
2140
2141        return (tclass == HDF5Constants.H5T_COMPOUND || tclass == HDF5Constants.H5T_ENUM || tclass == HDF5Constants.H5T_VLEN || tclass == HDF5Constants.H5T_ARRAY);
2142    }
2143
2144    private boolean datatypeIsAtomic(long tid) {
2145        return !datatypeIsComplex(tid) || isOpaque() || isBitField();
2146    }
2147}