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 COPYING file, which can be found  *
009 * at the root of the source code distribution tree,                         *
010 * or in https://www.hdfgroup.org/licenses.                                  *
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.math.BigDecimal;
019import java.math.BigInteger;
020import java.math.MathContext;
021import java.util.ArrayList;
022import java.util.Arrays;
023import java.util.BitSet;
024import java.util.HashMap;
025import java.util.Iterator;
026import java.util.List;
027import java.util.Map.Entry;
028import java.util.Objects;
029import java.util.Vector;
030
031import hdf.object.Attribute;
032import hdf.object.CompoundDS;
033import hdf.object.Datatype;
034import hdf.object.FileFormat;
035import hdf.object.h5.H5MetaDataContainer;
036
037import hdf.hdf5lib.H5;
038import hdf.hdf5lib.HDF5Constants;
039import hdf.hdf5lib.HDFArray;
040import hdf.hdf5lib.HDFNativeData;
041import hdf.hdf5lib.exceptions.HDF5Exception;
042import hdf.hdf5lib.exceptions.HDF5LibraryException;
043import hdf.hdf5lib.structs.H5O_info_t;
044import hdf.hdf5lib.structs.H5O_token_t;
045
046import org.slf4j.Logger;
047import org.slf4j.LoggerFactory;
048
049/**
050 * This class defines HDF5 datatype characteristics and APIs for a data type. This class provides several
051 * methods to convert an HDF5 datatype identifier to a datatype object, and vice versa. A datatype object is
052 * described by four basic fields: datatype class, size, byte order, and sign, while an HDF5 datatype is
053 * presented by a datatype identifier.
054 *
055 * @version 1.1 9/4/2007
056 * @author Peter X. Cao
057 */
058public class H5Datatype extends Datatype {
059    private static final long serialVersionUID = -750546422258749792L;
060
061    private static final Logger log = LoggerFactory.getLogger(H5Datatype.class);
062
063    /**
064     * The metadata object for this data object. Members of the metadata are instances of Attribute.
065     */
066    private H5MetaDataContainer objMetadata;
067
068    /**
069     * The dimension sizes of the reference object
070     */
071    protected long[] refdims;
072
073    /** the datatype is an object reference */
074    private boolean isRefObj = false;
075
076    /** the datatype is a region reference */
077    private boolean isRegRef = false;
078
079    /** the datatype is a standard reference */
080    private boolean isStdRef = false;
081
082    /** the object properties */
083    private H5O_info_t objInfo;
084
085    /**
086     * The native class of the datatype.
087     */
088    private int nativeClass = -1;
089
090    /** The native Precision properties of the number datatype. */
091    private long nativePrecision = 0;
092    /** The native Offset properties of the number datatype. */
093    private int nativeOffset = -1;
094    /** The native PadLSB properties of the number datatype. */
095    private int nativePadLSB = -1;
096    /** The native PadMSB properties of the number datatype. */
097    private int nativePadMSB = -1;
098
099    /** The native ebias properties of the float datatype. */
100    private long nativeFPebias = 0;
101    /** The native spos properties of the float datatype. */
102    private long nativeFPspos = -1;
103    /** The native epos properties of the float datatype. */
104    private long nativeFPepos = -1;
105    /** The native esize properties of the float datatype. */
106    private long nativeFPesize = -1;
107    /** The native mpos properties of the float datatype. */
108    private long nativeFPmpos = -1;
109    /** The native msize properties of the float datatype. */
110    private long nativeFPmsize = -1;
111    /** The native norm properties of the float datatype. */
112    private int nativeFPnorm = -1;
113    /** The native inpad properties of the float datatype. */
114    private int nativeFPinpad = -1;
115
116    /** The native padding properties of the string datatype. */
117    private int nativeStrPad = -1;
118    /** The native CSET properties of the string datatype. */
119    private int nativeStrCSET = -1;
120
121    /**
122     * The tag for an opaque datatype.
123     */
124    private String opaqueTag = null;
125
126    /**
127     * Constructs an named HDF5 data type object for a given file, dataset name and group path. The datatype
128     * object represents an existing named datatype in file. For example,
129     *
130     * <pre>
131     * new H5Datatype(file, "dtype1", "/g0")
132     * </pre>
133     *
134     * constructs a datatype object that corresponds to the dataset,"dset1", at group "/g0".
135     *
136     * @param theFile
137     *                the file that contains the datatype.
138     * @param theName
139     *                the name of the dataset such as "dset1".
140     * @param thePath
141     *                the group path to the dataset such as "/g0/".
142     */
143    public H5Datatype(FileFormat theFile, String theName, String thePath)
144    {
145        this(theFile, theName, thePath, null);
146    }
147
148    /**
149     * @deprecated Not for public use in the future. <br>
150     *             Using {@link #H5Datatype(FileFormat, String, String)}
151     * @param theFile
152     *                the file that contains the datatype.
153     * @param theName
154     *                the name of the dataset such as "dset1".
155     * @param thePath
156     *                the group path to the dataset such as "/g0/".
157     * @param oid
158     *                the oid of the dataset.
159     */
160    @Deprecated
161    public H5Datatype(FileFormat theFile, String theName, String thePath, long[] oid)
162    {
163        super(theFile, theName, thePath, oid);
164        objMetadata = new H5MetaDataContainer(theFile, theName, thePath, this);
165
166        if (theFile != null) {
167            if (oid == null) {
168                // retrieve the object ID
169                byte[] refBuf = null;
170                try {
171                    refBuf =
172                        H5.H5Rcreate_object(theFile.getFID(), this.getFullName(), HDF5Constants.H5P_DEFAULT);
173                    this.oid = HDFNativeData.byteToLong(refBuf);
174                    log.trace("constructor REF {} to OID {}", refBuf, this.oid);
175                }
176                catch (Exception ex) {
177                    log.debug("constructor ID {} for {} failed H5Rcreate_object", theFile.getFID(),
178                              this.getFullName());
179                }
180                finally {
181                    if (refBuf != null)
182                        H5.H5Rdestroy(refBuf);
183                }
184            }
185            log.trace("constructor OID {}", this.oid);
186            try {
187                objInfo = H5.H5Oget_info_by_name(theFile.getFID(), this.getFullName(),
188                                                 HDF5Constants.H5O_INFO_BASIC, HDF5Constants.H5P_DEFAULT);
189            }
190            catch (Exception ex) {
191                objInfo = new H5O_info_t(-1L, null, 0, 0, 0L, 0L, 0L, 0L, 0L);
192            }
193
194            long tid = HDF5Constants.H5I_INVALID_HID;
195            try {
196                tid = open();
197            }
198            catch (Exception ex) {
199                log.debug("constructor H5Topen() failure");
200            }
201            finally {
202                close(tid);
203            }
204        }
205        else {
206            this.oid = null;
207            objInfo  = new H5O_info_t(-1L, null, 0, 0, 0L, 0L, 0L, 0L, 0L);
208        }
209    }
210
211    /**
212     * Constructs a Datatype with specified class, size, byte order and sign. The following is a list of a few
213     * examples of H5Datatype. <ol> <li>to create unsigned native integer<br> H5Datatype type = new
214     * H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE); <li>to create
215     * 16-bit signed integer with big endian<br> H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2,
216     * Datatype.ORDER_BE, Datatype.NATIVE); <li>to create native float<br> H5Datatype type = new
217     * H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE); <li>to create
218     * 64-bit double<br> H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE,
219     * Datatype.NATIVE);
220     * </ol>
221     *
222     * @param tclass
223     *               the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
224     * @param tsize
225     *               the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. Valid values
226     * are NATIVE or a positive value. For string datatypes, -1 is also a valid value (to create a
227     *               variable-length string).
228     * @param torder
229     *               the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
230     * ORDER_NONE and NATIVE.
231     * @param tsign
232     *               the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
233     * @throws Exception
234     *                   if there is an error
235     */
236    public H5Datatype(int tclass, int tsize, int torder, int tsign) throws Exception
237    {
238        this(tclass, tsize, torder, tsign, null);
239    }
240
241    /**
242     * Constructs a Datatype with specified class, size, byte order and sign. The following is a list of a few
243     * examples of H5Datatype. <ol> <li>to create unsigned native integer<br> H5Datatype type = new
244     * H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE); <li>to create
245     * 16-bit signed integer with big endian<br> H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2,
246     * Datatype.ORDER_BE, Datatype.NATIVE); <li>to create native float<br> H5Datatype type = new
247     * H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE); <li>to create
248     * 64-bit double<br> H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE,
249     * Datatype.NATIVE);
250     * </ol>
251     *
252     * @param tclass
253     *               the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
254     * @param tsize
255     *               the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. Valid values
256     * are NATIVE or a positive value. For string datatypes, -1 is also a valid value (to create a
257     *               variable-length string).
258     * @param torder
259     *               the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
260     * ORDER_NONE and NATIVE.
261     * @param tsign
262     *               the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
263     * @param tbase
264     *               the base datatype of the new datatype
265     * @throws Exception
266     *                   if there is an error
267     */
268    public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) throws Exception
269    {
270        this(tclass, tsize, torder, tsign, tbase, null);
271    }
272
273    /**
274     * Constructs a Datatype with specified class, size, byte order and sign. The following is a list of a few
275     * examples of H5Datatype. <ol> <li>to create unsigned native integer<br> H5Datatype type = new
276     * H5Dataype(Datatype.CLASS_INTEGER, Datatype.NATIVE, Datatype.NATIVE, Datatype.SIGN_NONE); <li>to create
277     * 16-bit signed integer with big endian<br> H5Datatype type = new H5Dataype(Datatype.CLASS_INTEGER, 2,
278     * Datatype.ORDER_BE, Datatype.NATIVE); <li>to create native float<br> H5Datatype type = new
279     * H5Dataype(Datatype.CLASS_FLOAT, Datatype.NATIVE, Datatype.NATIVE, Datatype.NATIVE); <li>to create
280     * 64-bit double<br> H5Datatype type = new H5Dataype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE,
281     * Datatype.NATIVE);
282     * </ol>
283     *
284     * @param tclass
285     *               the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
286     * @param tsize
287     *               the size of the datatype in bytes, e.g. for a 32-bit integer, the size is 4. Valid values
288     * are NATIVE or a positive value. For string datatypes, -1 is also a valid value (to create a
289     *               variable-length string).
290     * @param torder
291     *               the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
292     * ORDER_NONE and NATIVE.
293     * @param tsign
294     *               the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
295     * @param tbase
296     *               the base datatype of the new datatype
297     * @param pbase
298     *               the parent datatype of the new datatype
299     * @throws Exception
300     *                   if there is an error
301     */
302    public H5Datatype(int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase)
303        throws Exception
304    {
305        super(tclass, tsize, torder, tsign, tbase, pbase);
306        datatypeDescription = getDescription();
307    }
308
309    /**
310     * Constructs a Datatype with a given native datatype identifier. For example, if the datatype identifier
311     * is a 32-bit unsigned integer created from HDF5,
312     *
313     * <pre>
314     * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
315     * Datatype dtype = new Datatype(tid);
316     * </pre>
317     *
318     * will construct a datatype equivalent to new Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE,
319     * Datatype.SIGN_NONE);
320     *
321     * @see #fromNative(long nativeID)
322     * @param theFile
323     *                 the file that contains the datatype.
324     * @param nativeID
325     *                 the native datatype identifier.
326     * @throws Exception
327     *                   if there is an error
328     */
329    public H5Datatype(FileFormat theFile, long nativeID) throws Exception { this(theFile, nativeID, null); }
330
331    /**
332     * Constructs a Datatype with a given native datatype identifier. For example, if the datatype identifier
333     * is a 32-bit unsigned integer created from HDF5,
334     *
335     * <pre>
336     * int tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_UNINT32);
337     * Datatype dtype = new Datatype(tid);
338     * </pre>
339     *
340     * will construct a datatype equivalent to new Datatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE,
341     * Datatype.SIGN_NONE);
342     *
343     * @see #fromNative(long nativeID)
344     * @param theFile
345     *                 the file that contains the datatype.
346     * @param nativeID
347     *                 the native datatype identifier.
348     * @param pbase
349     *                 the parent datatype of the new datatype
350     * @throws Exception
351     *                   if there is an error
352     */
353    public H5Datatype(FileFormat theFile, long nativeID, Datatype pbase) throws Exception
354    {
355        super(theFile, nativeID, pbase);
356        fromNative(nativeID);
357        datatypeDescription = getDescription();
358    }
359
360    /**
361     * Opens access to a named datatype. It calls H5.H5Topen(loc, name).
362     *
363     * @return the datatype identifier if successful; otherwise returns negative value.
364     * @see hdf.hdf5lib.H5#H5Topen(long, String, long)
365     */
366    @Override
367    public long open()
368    {
369        long tid = HDF5Constants.H5I_INVALID_HID;
370
371        if (fileFormat != null) {
372            try {
373                tid = H5.H5Topen(getFID(), getFullName(), HDF5Constants.H5P_DEFAULT);
374                fromNative(tid);
375                log.trace("open(): tid={}", tid);
376            }
377            catch (HDF5Exception ex) {
378                log.debug("open(): Failed to open datatype {}", getFullName(), ex);
379                tid = HDF5Constants.H5I_INVALID_HID;
380            }
381        }
382
383        return tid;
384    }
385
386    /**
387     * Closes a datatype identifier. It calls H5.H5close(tid).
388     *
389     * @param tid
390     *            the datatype ID to close
391     */
392    @Override
393    public void close(long tid)
394    {
395        if (tid >= 0) {
396            try {
397                H5.H5Tclose(tid);
398            }
399            catch (HDF5Exception ex) {
400                log.debug("close(): H5Tclose(tid {}) failure: ", tid, ex);
401            }
402        }
403    }
404
405    /**
406     * Get the token for this object.
407     *
408     * @return true if it has any attributes, false otherwise.
409     */
410    public long[] getToken()
411    {
412        H5O_token_t token = objInfo.token;
413        return HDFNativeData.byteToLong(token.data);
414    }
415
416    /**
417     * Check if the object has any attributes attached.
418     *
419     * @return true if it has any attributes, false otherwise.
420     */
421    @Override
422    public boolean hasAttribute()
423    {
424        objInfo.num_attrs = objMetadata.getObjectAttributeSize();
425
426        if (objInfo.num_attrs < 0) {
427            long tid = open();
428            if (tid > 0) {
429                try {
430                    objInfo = H5.H5Oget_info(tid);
431                }
432                catch (Exception ex) {
433                    objInfo.num_attrs = 0;
434                    log.debug("hasAttribute(): get object info failure: ", ex);
435                }
436                finally {
437                    close(tid);
438                }
439                objMetadata.setObjectAttributeSize((int)objInfo.num_attrs);
440            }
441            else {
442                log.debug("hasAttribute(): could not open group");
443            }
444        }
445
446        log.trace("hasAttribute(): nAttributes={}", objInfo.num_attrs);
447        return (objInfo.num_attrs > 0);
448    }
449
450    /**
451     * Converts values in an Enumeration Datatype to names. This method searches the identified enumeration
452     * datatype for the values appearing in <code>inValues</code> and returns the names corresponding to those
453     * values. If a given value is not found in the enumeration datatype, the name corresponding to that value
454     * will be set to <code>"ENUM ERR value"</code> in the string array that is returned. If the method fails
455     * in general, null will be returned instead of a String array. An empty <code>inValues</code> parameter
456     * would cause general failure.
457     *
458     * @param inValues
459     *                 The array of enumerations values to be converted.
460     * @return The string array of names if successful; otherwise return null.
461     * @throws HDF5Exception
462     *                       If there is an error at the HDF5 library level.
463     */
464    public String[] convertEnumValueToName(Object inValues) throws HDF5Exception
465    {
466        log.trace("convertEnumValueToName() inValues={} start", inValues);
467
468        if (inValues == null) {
469            log.debug("convertEnumValueToName() failure: in values null ");
470            return null;
471        }
472
473        int inSize        = 0;
474        String[] outNames = null;
475        String cName      = inValues.getClass().getName();
476        boolean isArray   = cName.lastIndexOf('[') >= 0;
477        if (isArray)
478            inSize = Array.getLength(inValues);
479        else
480            inSize = 1;
481
482        if (inSize <= 0) {
483            log.debug("convertEnumValueToName() failure: inSize length invalid");
484            log.debug("convertEnumValueToName(): inValues={} inSize={}", inValues, inSize);
485            return null;
486        }
487
488        if (enumMembers == null || enumMembers.size() <= 0) {
489            log.debug("convertEnumValueToName(): no members");
490            return null;
491        }
492
493        log.trace("convertEnumValueToName(): inSize={} nMembers={} enums={}", inSize, enumMembers.size(),
494                  enumMembers);
495        outNames = new String[inSize];
496        for (int i = 0; i < inSize; i++) {
497            if (isArray) {
498                if (enumMembers.containsKey(String.valueOf(Array.get(inValues, i))))
499                    outNames[i] = enumMembers.get(String.valueOf(Array.get(inValues, i)));
500                else
501                    outNames[i] = "**ENUM ERR " + Array.get(inValues, i) + "**";
502            }
503            else {
504                if (enumMembers.containsKey(String.valueOf(inValues)))
505                    outNames[i] = enumMembers.get(String.valueOf(inValues));
506                else
507                    outNames[i] = "**ENUM ERR " + inValues + "**";
508            }
509        }
510
511        return outNames;
512    }
513
514    /**
515     * Converts names in an Enumeration Datatype to values. This method searches the identified enumeration
516     * datatype for the names appearing in <code>inValues</code> and returns the values corresponding to those
517     * names.
518     *
519     * @param in
520     *           The array of enumerations names to be converted.
521     * @return The int array of values if successful; otherwise return null.
522     * @throws HDF5Exception
523     *                       If there is an error at the HDF5 library level.
524     */
525    public Object[] convertEnumNameToValue(String[] in) throws HDF5Exception
526    {
527        int size = 0;
528
529        if (in == null) {
530            log.debug("convertEnumNameToValue() failure: in values null");
531            return null;
532        }
533
534        if ((size = Array.getLength(in)) <= 0) {
535            log.debug("convertEnumNameToValue() failure: in size not valid");
536            return null;
537        }
538
539        if (enumMembers == null || enumMembers.size() <= 0) {
540            log.debug("convertEnumNameToValue(): no members");
541            return null;
542        }
543
544        Object[] out = null;
545        if (datatypeSize == 1)
546            out = new Byte[size];
547        else if (datatypeSize == 2)
548            out = new Short[size];
549        else if (datatypeSize == 4)
550            out = new Integer[size];
551        else if (datatypeSize == 8)
552            out = new Long[size];
553        else
554            out = new Object[size];
555
556        for (int i = 0; i < size; i++) {
557            if (in[i] == null || in[i].length() <= 0)
558                continue;
559
560            for (Entry<String, String> entry : enumMembers.entrySet()) {
561                if (Objects.equals(in[i], entry.getValue())) {
562                    if (datatypeSize == 1) {
563                        log.trace("convertEnumNameToValue(): ENUM is H5T_NATIVE_INT8");
564                        out[i] = Byte.parseByte(entry.getKey());
565                    }
566                    else if (datatypeSize == 2) {
567                        log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT16");
568                        out[i] = Short.parseShort(entry.getKey());
569                    }
570                    else if (datatypeSize == 4) {
571                        log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT32");
572                        out[i] = Integer.parseInt(entry.getKey());
573                    }
574                    else if (datatypeSize == 8) {
575                        log.trace("convertEnumNameToValue(): CLASS_INT-ENUM is H5T_NATIVE_INT64");
576                        out[i] = Long.parseLong(entry.getKey());
577                    }
578                    else {
579                        log.debug("convertEnumNameToValue(): enum datatypeSize incorrect");
580                        out[i] = -1;
581                    }
582                    break;
583                }
584            }
585        }
586
587        return out;
588    }
589
590    /**
591     * Convert from an array of BigDecimal into an array of bytes
592     *
593     * @param start
594     *              The position in the input array of BigDecimal to start
595     * @param len
596     *              The number of 'BigDecimal' to convert
597     * @param data
598     *              The input array of BigDecimal
599     * @return an array of bytes
600     */
601    public byte[] bigDecimalToByte(int start, int len, BigDecimal[] data)
602    {
603        int ii;
604        byte[] bd      = new byte[(int)datatypeSize];
605        byte[] bdconv  = new byte[(int)datatypeSize];
606        byte[] bdbytes = new byte[(int)datatypeSize * len];
607
608        for (ii = 0; ii < len; ii++) {
609            BigDecimal entry = data[start + ii];
610            bdconv           = convertBigDecimalToByte(entry);
611            /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */
612            if (datatypeOrder == ORDER_BE) {
613                int k = 0;
614                for (int j = (int)datatypeSize - 1; j >= 0; j--)
615                    bd[k++] = bdconv[j];
616            }
617            else {
618                try {
619                    System.arraycopy(bdconv, 0, bd, 0, (int)datatypeSize);
620                }
621                catch (Exception err) {
622                    log.trace("bigDecimalToByte(): arraycopy failure: ", err);
623                }
624            }
625            try {
626                System.arraycopy(bd, 0, bdbytes, ii * 16, 16);
627            }
628            catch (Exception err) {
629                log.trace("bigDecimalToByte(): arraycopy failure: ", err);
630            }
631        }
632        return bdbytes;
633    }
634
635    /**
636     * Convert from a single BigDecimal object from an array of BigDecimal into an array of bytes
637     *
638     * @param start
639     *              The position in the input array of BigDecimal to start
640     * @param data
641     *              The input Float
642     * @return an array of bytes
643     */
644    public byte[] bigDecimalToByte(BigDecimal[] data, int start)
645    {
646        byte[] bdbytes = new byte[(int)datatypeSize];
647        bdbytes        = bigDecimalToByte(start, 1, data);
648        return bdbytes;
649    }
650
651    /**
652     * Convert a BigDecimal to a byte array .
653     *
654     * @param num
655     *            The BigDecimal number to convert
656     * @return A byte array representing the BigDecimal.
657     */
658    public byte[] convertBigDecimalToByte(BigDecimal num)
659    {
660        BigInteger sig = new BigInteger(num.unscaledValue().toString());
661        byte[] bsig    = sig.toByteArray();
662        int scale      = num.scale();
663        byte[] bscale =
664            new byte[] {(byte)(scale >>> 24), (byte)(scale >>> 16), (byte)(scale >>> 8), (byte)(scale)};
665        byte[] both = new byte[bscale.length + bsig.length];
666        try {
667            System.arraycopy(bscale, 0, both, 0, bscale.length);
668            System.arraycopy(bsig, 0, both, bscale.length, bsig.length);
669        }
670        catch (Exception err) {
671            log.trace("convertBigDecimalToByte(): arraycopy failure: ", err);
672        }
673        return both;
674    }
675
676    /**
677     * Convert a range from an array of bytes into an array of BigDecimal
678     *
679     * @param start
680     *              The position in the input array of bytes to start
681     * @param len
682     *              The number of 'BigDecimal' to convert
683     * @param data
684     *              The input array of bytes
685     * @return an array of 'len' BigDecimal
686     */
687    public BigDecimal[] byteToBigDecimal(int start, int len, byte[] data)
688    {
689        int ii;
690        byte[] bd            = new byte[(int)datatypeSize];
691        BigDecimal[] BDarray = new BigDecimal[len];
692
693        for (ii = 0; ii < len; ii++) {
694            int rawpos = (start + ii) * (int)datatypeSize;
695            /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */
696            if (datatypeOrder == ORDER_BE) {
697                int k = 0;
698                for (int j = (int)datatypeSize - 1; j >= 0; j--)
699                    bd[k++] = data[rawpos + j];
700            }
701            else {
702                try {
703                    System.arraycopy(data, rawpos, bd, 0, (int)datatypeSize);
704                }
705                catch (Exception err) {
706                    log.trace("byteToBigDecimal(): arraycopy failure: ", err);
707                }
708            }
709            BDarray[ii] = convertByteToBigDecimal(bd);
710        }
711        return BDarray;
712    }
713
714    /**
715     * Convert 4 bytes from an array of bytes into a single BigDecimal
716     *
717     * @param start
718     *              The position in the input array of bytes to start
719     * @param data
720     *              The input array of bytes
721     * @return The BigDecimal value of the bytes.
722     */
723    public BigDecimal byteToBigDecimal(byte[] data, int start)
724    {
725        BigDecimal[] bdval = new BigDecimal[1];
726        bdval              = byteToBigDecimal(start, 1, data);
727        return (bdval[0]);
728    }
729
730    /**
731     * Convert byte array data to a BigDecimal.
732     *
733     * @param raw
734     *            The byte array to convert to a BigDecimal
735     * @return A BigDecimal representing the byte array.
736     */
737    public BigDecimal convertByteToBigDecimal(byte[] raw)
738    {
739        BitSet rawset = BitSet.valueOf(raw);
740
741        boolean sign       = rawset.get(nativeOffset + (int)nativeFPspos);
742        BitSet mantissaset = rawset.get(nativeOffset + (int)nativeFPmpos,
743                                        nativeOffset + (int)nativeFPmpos + (int)nativeFPmsize);
744        BitSet exponentset = rawset.get(nativeOffset + (int)nativeFPepos,
745                                        nativeOffset + (int)nativeFPepos + (int)nativeFPesize);
746        byte[] expraw      = Arrays.copyOf(exponentset.toByteArray(), (int)(nativeFPesize + 7) / 8);
747        byte[] bexp        = new byte[expraw.length];
748        /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */
749        if (datatypeOrder == ORDER_LE) {
750            int k = 0;
751            for (int j = expraw.length - 1; j >= 0; j--)
752                bexp[k++] = expraw[j];
753        }
754        else {
755            try {
756                System.arraycopy(expraw, 0, bexp, 0, expraw.length);
757            }
758            catch (Exception err) {
759                log.trace("convertByteToBigDecimal(): arraycopy failure: ", err);
760            }
761        }
762        BigInteger bscale = new BigInteger(bexp);
763        long scale        = bscale.longValue();
764        scale -= nativeFPebias;
765        double powscale = Math.pow(2, scale);
766
767        byte[] manraw = Arrays.copyOf(mantissaset.toByteArray(), (int)(nativeFPmsize + 7) / 8);
768        byte[] bman   = new byte[manraw.length];
769        /* bitsets operate assuming LE order, BigInteger/BigDecimal expect BE */
770        if (datatypeOrder == ORDER_BE) {
771            int k = 0;
772            for (int j = manraw.length - 1; j >= 0; j--)
773                bman[k++] = manraw[j];
774        }
775        else {
776            try {
777                System.arraycopy(manraw, 0, bman, 0, manraw.length);
778            }
779            catch (Exception err) {
780                log.trace("convertByteToBigDecimal(): arraycopy failure: ", err);
781            }
782        }
783        BitSet manset = BitSet.valueOf(bman);
784
785        // calculate mantissa value
786        double val = 0.0;
787        for (int i = 0; i < (int)nativeFPmsize; i++) {
788            if (manset.get((int)nativeFPmsize - 1 - i))
789                val += Math.pow(2, -(i));
790        }
791        if (nativeFPnorm == HDF5Constants.H5T_NORM_IMPLIED || nativeFPnorm == HDF5Constants.H5T_NORM_MSBSET)
792            val += 1;
793        BigDecimal sig = BigDecimal.valueOf(val);
794        if (sign)
795            sig.negate(MathContext.DECIMAL128);
796        return sig.multiply(new BigDecimal(powscale, MathContext.DECIMAL128));
797    }
798
799    /*
800     * (non-Javadoc)
801     * @see hdf.object.Datatype#fromNative(int)
802     */
803    @Override
804    public void fromNative(long tid)
805    {
806        log.trace("fromNative(): start: tid={}", tid);
807        long tsize      = -1;
808        int torder      = -1;
809        boolean isChar  = false;
810        boolean isUchar = false;
811
812        if (tid < 0) {
813            datatypeClass = CLASS_NO_CLASS;
814        }
815        else {
816            try {
817                nativeClass   = H5.H5Tget_class(tid);
818                tsize         = H5.H5Tget_size(tid);
819                isVariableStr = H5.H5Tis_variable_str(tid);
820                isVLEN        = false;
821                log.trace("fromNative(): tclass={}, tsize={}, torder={}, isVLEN={}", nativeClass, tsize,
822                          torder, isVLEN);
823                if (H5.H5Tcommitted(tid)) {
824                    isNamed = true;
825                    try {
826                        setFullname(null, H5.H5Iget_name(tid));
827                    }
828                    catch (Exception nex) {
829                        log.debug("fromNative(): setName failure: {}", nex.getMessage());
830                    }
831                    log.trace("fromNative(): path={} name={}", this.getPath(), this.getName());
832                }
833                log.trace("fromNative(): isNamed={}", isNamed());
834            }
835            catch (Exception ex) {
836                log.debug("fromNative(): failure: ", ex);
837                datatypeClass = CLASS_NO_CLASS;
838            }
839
840            try {
841                isUchar = H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_UCHAR);
842                isChar  = (H5.H5Tequal(tid, HDF5Constants.H5T_NATIVE_CHAR) || isUchar);
843                log.trace("fromNative(): tclass={}, tsize={}, torder={}, isUchar={}, isChar={}", nativeClass,
844                          tsize, torder, isUchar, isChar);
845            }
846            catch (Exception ex) {
847                log.debug("fromNative(): native char type failure: ", ex);
848            }
849
850            datatypeOrder    = HDF5Constants.H5T_ORDER_NONE;
851            boolean IsAtomic = datatypeClassIsAtomic(nativeClass);
852            if (IsAtomic || (nativeClass == HDF5Constants.H5T_COMPOUND)) {
853                try {
854                    torder        = H5.H5Tget_order(tid);
855                    datatypeOrder = (torder == HDF5Constants.H5T_ORDER_BE) ? ORDER_BE : ORDER_LE;
856                }
857                catch (Exception ex) {
858                    log.debug("fromNative(): get_order failure: ", ex);
859                }
860            }
861
862            if (IsAtomic && !datatypeClassIsOpaque(nativeClass)) {
863                try {
864                    nativePrecision = H5.H5Tget_precision_long(tid);
865                }
866                catch (Exception ex) {
867                    log.debug("fromNative(): get_precision failure: ", ex);
868                }
869
870                try {
871                    nativeOffset = H5.H5Tget_offset(tid);
872                }
873                catch (Exception ex) {
874                    log.debug("fromNative(): get_offset failure: ", ex);
875                }
876
877                try {
878                    int[] pads = new int[2];
879                    H5.H5Tget_pad(tid, pads);
880                    nativePadLSB = pads[0];
881                    nativePadMSB = pads[1];
882                }
883                catch (Exception ex) {
884                    log.debug("fromNative(): get_pad failure: ", ex);
885                }
886            }
887
888            log.trace(
889                "fromNative(): isUchar={}, nativePrecision={}, nativeOffset={}, nativePadLSB={}, nativePadMSB={}",
890                isUchar, nativePrecision, nativeOffset, nativePadLSB, nativePadMSB);
891
892            datatypeSign = NATIVE; // default
893            if (nativeClass == HDF5Constants.H5T_ARRAY) {
894                long tmptid   = HDF5Constants.H5I_INVALID_HID;
895                datatypeClass = CLASS_ARRAY;
896                try {
897                    int ndims = H5.H5Tget_array_ndims(tid);
898                    arrayDims = new long[ndims];
899                    H5.H5Tget_array_dims(tid, arrayDims);
900
901                    tmptid              = H5.H5Tget_super(tid);
902                    int nativeBaseClass = H5.H5Tget_class(tmptid);
903                    if (nativeBaseClass == HDF5Constants.H5T_REFERENCE)
904                        baseType = new H5ReferenceType(this.fileFormat, 1, tmptid);
905                    else
906                        baseType = new H5Datatype(this.fileFormat, tmptid, this);
907                    if (baseType == null) {
908                        log.debug("fromNative(): ARRAY datatype has null base type");
909                        throw new Exception("Datatype (ARRAY) has no base datatype");
910                    }
911
912                    datatypeSign = baseType.getDatatypeSign();
913                }
914                catch (Exception ex) {
915                    log.debug("fromNative(): array type failure: ", ex);
916                }
917                finally {
918                    close(tmptid);
919                }
920            }
921            else if (nativeClass == HDF5Constants.H5T_COMPOUND) {
922                datatypeClass = CLASS_COMPOUND;
923
924                try {
925                    int nMembers          = H5.H5Tget_nmembers(tid);
926                    compoundMemberNames   = new Vector<>(nMembers);
927                    compoundMemberTypes   = new Vector<>(nMembers);
928                    compoundMemberOffsets = new Vector<>(nMembers);
929                    log.trace("fromNative(): compound type nMembers={} start", nMembers);
930
931                    for (int i = 0; i < nMembers; i++) {
932                        String memberName = H5.H5Tget_member_name(tid, i);
933                        log.trace("fromNative(): compound type [{}] name={} start", i, memberName);
934                        long memberOffset     = H5.H5Tget_member_offset(tid, i);
935                        long memberID         = HDF5Constants.H5I_INVALID_HID;
936                        H5Datatype membertype = null;
937                        try {
938                            memberID              = H5.H5Tget_member_type(tid, i);
939                            int nativeMemberClass = H5.H5Tget_class(memberID);
940                            if (nativeMemberClass == HDF5Constants.H5T_REFERENCE)
941                                membertype = new H5ReferenceType(this.fileFormat, 1, memberID);
942                            else
943                                membertype = new H5Datatype(this.fileFormat, memberID, this);
944                        }
945                        catch (Exception ex1) {
946                            log.debug("fromNative(): compound type failure: ", ex1);
947                        }
948                        finally {
949                            close(memberID);
950                        }
951
952                        compoundMemberNames.add(i, memberName);
953                        compoundMemberOffsets.add(i, memberOffset);
954                        compoundMemberTypes.add(i, membertype);
955                    }
956                }
957                catch (HDF5LibraryException ex) {
958                    log.debug("fromNative(): compound type failure: ", ex);
959                }
960            }
961            else if (nativeClass == HDF5Constants.H5T_INTEGER) {
962                datatypeClass = CLASS_INTEGER;
963                try {
964                    log.trace("fromNative(): integer type");
965                    int tsign    = H5.H5Tget_sign(tid);
966                    datatypeSign = (tsign == HDF5Constants.H5T_SGN_NONE) ? SIGN_NONE : SIGN_2;
967                }
968                catch (Exception ex) {
969                    log.debug("fromNative(): int type failure: ", ex);
970                }
971            }
972            else if (nativeClass == HDF5Constants.H5T_FLOAT) {
973                datatypeClass = CLASS_FLOAT;
974                try {
975                    nativeFPebias = H5.H5Tget_ebias_long(tid);
976                }
977                catch (Exception ex) {
978                    log.debug("fromNative(): get_ebias failure: ", ex);
979                }
980                try {
981                    long[] fields = new long[5];
982                    H5.H5Tget_fields(tid, fields);
983                    nativeFPspos  = fields[0];
984                    nativeFPepos  = fields[1];
985                    nativeFPesize = fields[2];
986                    nativeFPmpos  = fields[3];
987                    nativeFPmsize = fields[4];
988                }
989                catch (Exception ex) {
990                    log.debug("fromNative(): get_fields failure: ", ex);
991                }
992                try {
993                    nativeFPnorm = H5.H5Tget_norm(tid);
994                }
995                catch (Exception ex) {
996                    log.debug("fromNative(): get_norm failure: ", ex);
997                }
998                try {
999                    nativeFPinpad = H5.H5Tget_inpad(tid);
1000                }
1001                catch (Exception ex) {
1002                    log.debug("fromNative(): get_inpad failure: ", ex);
1003                }
1004            }
1005            else if (isChar) {
1006                datatypeClass = CLASS_CHAR;
1007                datatypeSign  = (isUchar) ? SIGN_NONE : SIGN_2;
1008                log.trace("fromNative(): CLASS_CHAR:datatypeSign={}", datatypeSign);
1009            }
1010            else if (nativeClass == HDF5Constants.H5T_STRING) {
1011                datatypeClass = CLASS_STRING;
1012                try {
1013                    isVLEN = H5.H5Tdetect_class(tid, HDF5Constants.H5T_VLEN) || isVariableStr;
1014                    log.trace("fromNative(): H5T_STRING:var str type={}", isVLEN);
1015                    nativeStrPad = H5.H5Tget_strpad(tid);
1016                }
1017                catch (Exception ex) {
1018                    log.debug("fromNative(): var str type failure: ", ex);
1019                }
1020                try {
1021                    nativeStrCSET = H5.H5Tget_cset(tid);
1022                }
1023                catch (Exception ex) {
1024                    log.debug("fromNative(): H5T_STRING:get_cset failure: ", ex);
1025                }
1026                log.trace("fromNative(): H5T_STRING:nativeStrPad={}, nativeStrCSET={}", nativeStrPad,
1027                          nativeStrCSET);
1028            }
1029            else if (nativeClass == HDF5Constants.H5T_REFERENCE) {
1030                datatypeClass = CLASS_REFERENCE;
1031                log.trace("fromNative(): reference type");
1032                try {
1033                    isStdRef = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF);
1034                    log.trace("fromNative(): reference type is orig StdRef:{}", isStdRef);
1035                    if (H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF))
1036                        tsize = HDF5Constants.H5R_REF_BUF_SIZE;
1037                }
1038                catch (Exception ex) {
1039                    log.debug("fromNative(): H5T_STD_REF: ", ex);
1040                }
1041                try {
1042                    isRegRef = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG);
1043                    log.trace("fromNative(): reference type isRegRef:{}", isRegRef);
1044                    if (isRegRef)
1045                        tsize = HDF5Constants.H5R_DSET_REG_REF_BUF_SIZE;
1046                }
1047                catch (Exception ex) {
1048                    log.debug("fromNative(): H5T_STD_REF_DSETREG: ", ex);
1049                }
1050                try {
1051                    isRefObj = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_OBJ);
1052                    log.trace("fromNative(): reference type isRefObj:{}", isRefObj);
1053                    if (isRefObj)
1054                        tsize = HDF5Constants.H5R_OBJ_REF_BUF_SIZE;
1055                }
1056                catch (Exception ex) {
1057                    log.debug("fromNative(): H5T_STD_REF_OBJ: ", ex);
1058                }
1059            }
1060            else if (nativeClass == HDF5Constants.H5T_ENUM) {
1061                datatypeClass = CLASS_ENUM;
1062                long tmptid   = HDF5Constants.H5I_INVALID_HID;
1063                long basetid  = HDF5Constants.H5I_INVALID_HID;
1064                try {
1065                    log.trace("fromNative(): enum type");
1066                    basetid = H5.H5Tget_super(tid);
1067                    tmptid  = basetid;
1068                    basetid = H5.H5Tget_native_type(tmptid);
1069                    log.trace("fromNative(): enum type basetid={}", basetid);
1070                    if (basetid >= 0) {
1071                        baseType     = new H5Datatype(this.fileFormat, tmptid, this);
1072                        datatypeSign = baseType.getDatatypeSign();
1073                    }
1074                }
1075                catch (Exception ex) {
1076                    log.debug("fromNative(): enum type failure: ", ex);
1077                }
1078                finally {
1079                    close(tmptid);
1080                    close(basetid);
1081                }
1082                try {
1083                    int enumMemberCount = H5.H5Tget_nmembers(tid);
1084                    String name         = null;
1085                    String enumStr      = null;
1086                    byte[] val          = new byte[(int)tsize];
1087                    enumMembers         = new HashMap<>();
1088                    for (int i = 0; i < enumMemberCount; i++) {
1089                        name = H5.H5Tget_member_name(tid, i);
1090                        H5.H5Tget_member_value(tid, i, val);
1091                        switch ((int)H5.H5Tget_size(tid)) {
1092                        case 1:
1093                            enumStr = Byte.toString((HDFNativeData.byteToByte(val[0]))[0]);
1094                            break;
1095                        case 2:
1096                            enumStr = Short.toString((HDFNativeData.byteToShort(val))[0]);
1097                            break;
1098                        case 4:
1099                            enumStr = Integer.toString((HDFNativeData.byteToInt(val))[0]);
1100                            break;
1101                        case 8:
1102                            enumStr = Long.toString((HDFNativeData.byteToLong(val))[0]);
1103                            break;
1104                        default:
1105                            enumStr = "-1";
1106                            break;
1107                        }
1108                        enumMembers.put(enumStr, name);
1109                    }
1110                }
1111                catch (Exception ex) {
1112                    log.debug("fromNative(): enum type failure: ", ex);
1113                }
1114            }
1115            else if (nativeClass == HDF5Constants.H5T_VLEN) {
1116                long tmptid   = HDF5Constants.H5I_INVALID_HID;
1117                datatypeClass = CLASS_VLEN;
1118                isVLEN        = true;
1119                try {
1120                    log.trace("fromNative(): vlen type");
1121                    tmptid              = H5.H5Tget_super(tid);
1122                    int nativeBaseClass = H5.H5Tget_class(tmptid);
1123                    if (nativeBaseClass == HDF5Constants.H5T_REFERENCE)
1124                        baseType = new H5ReferenceType(this.fileFormat, 1, tmptid);
1125                    else
1126                        baseType = new H5Datatype(this.fileFormat, tmptid, this);
1127                    if (baseType == null) {
1128                        log.debug("fromNative(): VLEN datatype has null base type");
1129                        throw new Exception("Datatype (VLEN) has no base datatype");
1130                    }
1131
1132                    datatypeSign = baseType.getDatatypeSign();
1133                }
1134                catch (Exception ex) {
1135                    log.debug("fromNative(): vlen type failure: ", ex);
1136                }
1137                finally {
1138                    close(tmptid);
1139                }
1140            }
1141            else if (nativeClass == HDF5Constants.H5T_BITFIELD) {
1142                datatypeClass = CLASS_BITFIELD;
1143            }
1144            else if (nativeClass == HDF5Constants.H5T_OPAQUE) {
1145                datatypeClass = CLASS_OPAQUE;
1146
1147                try {
1148                    opaqueTag = H5.H5Tget_tag(tid);
1149                }
1150                catch (Exception ex) {
1151                    log.debug("fromNative(): opaque type tag retrieval failed: ", ex);
1152                    opaqueTag = null;
1153                }
1154            }
1155            else {
1156                log.debug("fromNative(): datatypeClass is unknown");
1157            }
1158
1159            datatypeSize = (isVLEN && !isVariableStr) ? HDF5Constants.H5T_VL_T : tsize;
1160        }
1161        if (datatypeSize == NATIVE)
1162            datatypeNATIVE = true;
1163        else
1164            datatypeNATIVE = false;
1165        log.trace("fromNative(): datatypeClass={} baseType={} datatypeSize={}", datatypeClass, baseType,
1166                  datatypeSize);
1167    }
1168
1169    /**
1170     * @param tid
1171     *            the datatype identification disk.
1172     * @return the memory datatype identifier if successful, and negative otherwise.
1173     */
1174    public static long toNative(long tid)
1175    {
1176        // data type information
1177        log.trace("toNative(): tid={} start", tid);
1178        long nativeID = HDF5Constants.H5I_INVALID_HID;
1179
1180        try {
1181            nativeID = H5.H5Tget_native_type(tid);
1182        }
1183        catch (Exception ex) {
1184            log.debug("toNative(): H5Tget_native_type(tid {}) failure: ", tid, ex);
1185        }
1186
1187        try {
1188            if (H5.H5Tis_variable_str(tid))
1189                H5.H5Tset_size(nativeID, HDF5Constants.H5T_VARIABLE);
1190        }
1191        catch (Exception ex) {
1192            log.debug("toNative(): var str type size failure: ", ex);
1193        }
1194
1195        return nativeID;
1196    }
1197
1198    /*
1199     * (non-Javadoc)
1200     * @see hdf.object.Datatype#createNative()
1201     */
1202    @SuppressWarnings("rawtypes")
1203    @Override
1204    public long createNative()
1205    {
1206        long tid    = HDF5Constants.H5I_INVALID_HID;
1207        long tmptid = HDF5Constants.H5I_INVALID_HID;
1208
1209        String the_path = getFullName();
1210        // isNamed == true should have non-null fileFormat
1211        if (isNamed()) {
1212            try {
1213                tid = H5.H5Topen(getFID(), the_path, HDF5Constants.H5P_DEFAULT);
1214            }
1215            catch (Exception ex) {
1216                log.debug("createNative(): name {} H5Topen failure: ", the_path, ex);
1217            }
1218        }
1219        else
1220            log.debug("createNative(): isNamed={} and named path={}", isNamed(), the_path);
1221
1222        if (tid >= 0)
1223            return tid;
1224
1225        log.trace("createNative(): datatypeClass={} datatypeSize={} baseType={}", datatypeClass, datatypeSize,
1226                  baseType);
1227
1228        switch (datatypeClass) {
1229        case CLASS_ARRAY:
1230            try {
1231                if (baseType == null) {
1232                    log.debug("createNative(): CLASS_ARRAY base type is NULL");
1233                    break;
1234                }
1235
1236                if ((tmptid = baseType.createNative()) < 0) {
1237                    log.debug("createNative(): failed to create native datatype for ARRAY base datatype");
1238                    break;
1239                }
1240
1241                tid = H5.H5Tarray_create(tmptid, arrayDims.length, arrayDims);
1242            }
1243            catch (Exception ex) {
1244                log.debug("createNative(): native array datatype creation failed: ", ex);
1245                if (tid >= 0)
1246                    close(tid);
1247                tid = HDF5Constants.H5I_INVALID_HID;
1248            }
1249            finally {
1250                close(tmptid);
1251            }
1252
1253            break;
1254        case CLASS_COMPOUND:
1255            try {
1256                tid = H5.H5Tcreate(CLASS_COMPOUND, datatypeSize);
1257
1258                for (int i = 0; i < compoundMemberTypes.size(); i++) {
1259                    H5Datatype memberType = null;
1260                    String memberName     = null;
1261                    long memberOffset     = -1;
1262
1263                    try {
1264                        memberType = (H5Datatype)compoundMemberTypes.get(i);
1265                    }
1266                    catch (Exception ex) {
1267                        log.debug("createNative(): get compound member[{}] type failure: ", i, ex);
1268                        memberType = null;
1269                    }
1270
1271                    try {
1272                        memberName = compoundMemberNames.get(i);
1273                    }
1274                    catch (Exception ex) {
1275                        log.debug("createNative(): get compound member[{}] name failure: ", i, ex);
1276                        memberName = null;
1277                    }
1278
1279                    try {
1280                        memberOffset = compoundMemberOffsets.get(i);
1281                    }
1282                    catch (Exception ex) {
1283                        log.debug("createNative(): get compound member[{}] offset failure: ", i, ex);
1284                        memberOffset = -1;
1285                    }
1286
1287                    long memberID = HDF5Constants.H5I_INVALID_HID;
1288                    try {
1289                        memberID = memberType.createNative();
1290                        log.trace("createNative(): {} member[{}] with offset={} ID={}: ", memberName, i,
1291                                  memberOffset, memberID);
1292
1293                        H5.H5Tinsert(tid, memberName, memberOffset, memberID);
1294                    }
1295                    catch (Exception ex) {
1296                        log.debug("createNative(): compound type member[{}] insertion failure: ", i, ex);
1297                    }
1298                    finally {
1299                        close(memberID);
1300                    }
1301                }
1302            }
1303            catch (Exception ex) {
1304                log.debug("createNative(): native compound datatype creation failed: ", ex);
1305                if (tid >= 0)
1306                    close(tid);
1307                tid = HDF5Constants.H5I_INVALID_HID;
1308            }
1309            break;
1310        case CLASS_INTEGER:
1311            log.trace("createNative(): CLASS_INT of size {}", datatypeSize);
1312
1313            try {
1314                switch ((int)datatypeSize) {
1315                case 1:
1316                    log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT8");
1317                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8);
1318                    break;
1319                case 2:
1320                    log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT16");
1321                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT16);
1322                    break;
1323                case 4:
1324                    log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT32");
1325                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32);
1326                    break;
1327                case 8:
1328                    log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT64");
1329                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT64);
1330                    break;
1331                default:
1332                    if (datatypeSize == NATIVE) {
1333                        datatypeNATIVE = true;
1334                        log.trace("createNative(): CLASS_INT is H5T_NATIVE_INT");
1335                        tid          = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT);
1336                        datatypeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT);
1337                    }
1338                    else {
1339                        datatypeNATIVE = false;
1340                        /* Custom sized integer */
1341                        tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT8);
1342                        H5.H5Tset_size(tid, datatypeSize);
1343                        H5.H5Tset_precision(tid, 8 * datatypeSize);
1344                    }
1345                    break;
1346                }
1347
1348                if (datatypeOrder == Datatype.ORDER_BE) {
1349                    log.trace("createNative(): CLASS_INT order is H5T_ORDER_BE");
1350                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
1351                }
1352                else if (datatypeOrder == Datatype.ORDER_LE) {
1353                    log.trace("createNative(): CLASS_INT order is H5T_ORDER_LE");
1354                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
1355                }
1356
1357                if (datatypeSign == Datatype.SIGN_NONE) {
1358                    log.trace("createNative(): CLASS_INT sign is H5T_SGN_NONE");
1359                    H5.H5Tset_sign(tid, HDF5Constants.H5T_SGN_NONE);
1360                }
1361            }
1362            catch (Exception ex) {
1363                log.debug("createNative(): native integer datatype creation failed: ", ex);
1364                if (tid >= 0)
1365                    close(tid);
1366                tid = -1;
1367            }
1368
1369            break;
1370        case CLASS_ENUM:
1371            log.trace("createNative(): CLASS_ENUM");
1372            try {
1373                if (baseType != null) {
1374                    if ((tmptid = baseType.createNative()) < 0) {
1375                        log.debug("createNative(): failed to create native type for ENUM base datatype");
1376                        break;
1377                    }
1378
1379                    tid = H5.H5Tenum_create(tmptid);
1380                }
1381                else {
1382                    if (datatypeSize == NATIVE) {
1383                        datatypeNATIVE = true;
1384                        datatypeSize   = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT);
1385                    }
1386                    else
1387                        datatypeNATIVE = false;
1388
1389                    tid = H5.H5Tcreate(HDF5Constants.H5T_ENUM, datatypeSize);
1390                }
1391
1392                if (datatypeOrder == Datatype.ORDER_BE) {
1393                    log.trace("createNative(): CLASS_ENUM order is H5T_ORDER_BE");
1394                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
1395                }
1396                else if (datatypeOrder == Datatype.ORDER_LE) {
1397                    log.trace("createNative(): CLASS_ENUM order is H5T_ORDER_LE");
1398                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
1399                }
1400
1401                if (datatypeSign == Datatype.SIGN_NONE) {
1402                    log.trace("createNative(): CLASS_ENUM sign is H5T_SGN_NONE");
1403                    H5.H5Tset_sign(tid, HDF5Constants.H5T_SGN_NONE);
1404                }
1405            }
1406            catch (Exception ex) {
1407                log.debug("createNative(): native enum datatype creation failed: ", ex);
1408                if (tid >= 0)
1409                    close(tid);
1410                tid = HDF5Constants.H5I_INVALID_HID;
1411            }
1412            finally {
1413                close(tmptid);
1414            }
1415
1416            break;
1417        case CLASS_FLOAT:
1418            try {
1419                if (datatypeSize > 8)
1420                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_LDOUBLE);
1421                else
1422                    tid = H5.H5Tcopy((datatypeSize == 8) ? HDF5Constants.H5T_NATIVE_DOUBLE
1423                                                         : HDF5Constants.H5T_NATIVE_FLOAT);
1424
1425                if (datatypeOrder == Datatype.ORDER_BE) {
1426                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
1427                }
1428                else if (datatypeOrder == Datatype.ORDER_LE) {
1429                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
1430                }
1431
1432                if (nativeFPebias > 0) {
1433                    H5.H5Tset_ebias(tid, nativeFPebias);
1434                }
1435
1436                if (nativeFPnorm >= 0) {
1437                    H5.H5Tset_norm(tid, nativeFPnorm);
1438                }
1439
1440                if (nativeFPinpad >= 0) {
1441                    H5.H5Tset_inpad(tid, nativeFPinpad);
1442                }
1443
1444                if ((nativeFPesize >= 0) && (nativeFPmsize >= 0)) {
1445                    H5.H5Tset_fields(tid, nativeFPspos, nativeFPmpos, nativeFPesize, nativeFPmpos,
1446                                     nativeFPmsize);
1447                }
1448            }
1449            catch (Exception ex) {
1450                log.debug("createNative(): native floating-point datatype creation failed: ", ex);
1451                if (tid >= 0)
1452                    close(tid);
1453                tid = HDF5Constants.H5I_INVALID_HID;
1454            }
1455
1456            break;
1457        case CLASS_CHAR:
1458            try {
1459                tid = H5.H5Tcopy((datatypeSign == Datatype.SIGN_NONE) ? HDF5Constants.H5T_NATIVE_UCHAR
1460                                                                      : HDF5Constants.H5T_NATIVE_CHAR);
1461            }
1462            catch (Exception ex) {
1463                log.debug("createNative(): native character datatype creation failed: ", ex);
1464                if (tid >= 0)
1465                    close(tid);
1466                tid = HDF5Constants.H5I_INVALID_HID;
1467            }
1468
1469            break;
1470        case CLASS_STRING:
1471            try {
1472                tid = H5.H5Tcopy(HDF5Constants.H5T_C_S1);
1473
1474                H5.H5Tset_size(tid, (isVLEN || datatypeSize < 0) ? HDF5Constants.H5T_VARIABLE : datatypeSize);
1475
1476                log.trace("createNative(): isVlenStr={} nativeStrPad={} nativeStrCSET={}", isVLEN,
1477                          nativeStrPad, nativeStrCSET);
1478
1479                H5.H5Tset_strpad(tid, (nativeStrPad >= 0) ? nativeStrPad : HDF5Constants.H5T_STR_NULLTERM);
1480
1481                if (nativeStrCSET >= 0) {
1482                    H5.H5Tset_cset(tid, nativeStrCSET);
1483                }
1484            }
1485            catch (Exception ex) {
1486                log.debug("createNative(): native string datatype creation failed: ", ex);
1487                if (tid >= 0)
1488                    close(tid);
1489                tid = HDF5Constants.H5I_INVALID_HID;
1490            }
1491
1492            break;
1493        case CLASS_REFERENCE:
1494            try {
1495                long objRefTypeSize  = H5.H5Tget_size(HDF5Constants.H5T_STD_REF_OBJ);
1496                long dsetRefTypeSize = H5.H5Tget_size(HDF5Constants.H5T_STD_REF_DSETREG);
1497                // use datatypeSize as which type to copy
1498                log.debug("createNative(): datatypeSize:{} ", datatypeSize);
1499                if (datatypeSize < 0 || datatypeSize > dsetRefTypeSize) {
1500                    tid = H5.H5Tcopy(HDF5Constants.H5T_STD_REF);
1501                    log.debug("createNative(): HDF5Constants.H5T_STD_REF");
1502                }
1503                else if (datatypeSize > objRefTypeSize) {
1504                    tid = H5.H5Tcopy(HDF5Constants.H5T_STD_REF_DSETREG);
1505                    log.debug("createNative(): HDF5Constants.H5T_STD_REF_DSETREG");
1506                }
1507                else {
1508                    tid = H5.H5Tcopy(HDF5Constants.H5T_STD_REF_OBJ);
1509                    log.debug("createNative(): HDF5Constants.H5T_STD_REF_OBJ");
1510                }
1511            }
1512            catch (Exception ex) {
1513                log.debug("createNative(): native reference datatype creation failed: ", ex);
1514                if (tid >= 0)
1515                    close(tid);
1516                tid = HDF5Constants.H5I_INVALID_HID;
1517            }
1518
1519            break;
1520        case CLASS_VLEN:
1521            try {
1522                if (baseType == null) {
1523                    log.debug("createNative(): CLASS_VLEN base type is NULL");
1524                    break;
1525                }
1526
1527                if ((tmptid = baseType.createNative()) < 0) {
1528                    log.debug("createNative(): failed to create native datatype for VLEN base datatype");
1529                    break;
1530                }
1531
1532                tid = H5.H5Tvlen_create(tmptid);
1533            }
1534            catch (Exception ex) {
1535                log.debug("createNative(): native variable-length datatype creation failed: ", ex);
1536                if (tid >= 0)
1537                    close(tid);
1538                tid = HDF5Constants.H5I_INVALID_HID;
1539            }
1540            finally {
1541                close(tmptid);
1542            }
1543
1544            break;
1545        case CLASS_BITFIELD:
1546            log.trace("createNative(): CLASS_BITFIELD size is {}", datatypeSize);
1547
1548            try {
1549                switch ((int)datatypeSize) {
1550                case 1:
1551                    log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B8");
1552                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B8);
1553                    break;
1554                case 2:
1555                    log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B16");
1556                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B16);
1557                    break;
1558                case 4:
1559                    log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B32");
1560                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B32);
1561                    break;
1562                case 8:
1563                    log.trace("createNative(): CLASS_BITFIELD is H5T_NATIVE_B64");
1564                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B64);
1565                    break;
1566                default:
1567                    if (datatypeSize == NATIVE) {
1568                        datatypeNATIVE = true;
1569                        datatypeSize   = 1;
1570                    }
1571                    else
1572                        datatypeNATIVE = false;
1573
1574                    /* Custom sized bitfield */
1575                    tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_B8);
1576                    H5.H5Tset_size(tid, datatypeSize);
1577                    H5.H5Tset_precision(tid, 8 * datatypeSize);
1578
1579                    break;
1580                }
1581
1582                if (datatypeOrder == Datatype.ORDER_BE) {
1583                    log.trace("createNative(): CLASS_BITFIELD order is H5T_ORDER_BE");
1584                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_BE);
1585                }
1586                else if (datatypeOrder == Datatype.ORDER_LE) {
1587                    log.trace("createNative(): CLASS_BITFIELD order is H5T_ORDER_LE");
1588                    H5.H5Tset_order(tid, HDF5Constants.H5T_ORDER_LE);
1589                }
1590            }
1591            catch (Exception ex) {
1592                log.debug("createNative(): native bitfield datatype creation failed: ", ex);
1593                if (tid >= 0)
1594                    close(tid);
1595                tid = HDF5Constants.H5I_INVALID_HID;
1596            }
1597
1598            break;
1599        case CLASS_OPAQUE:
1600            log.trace("createNative(): CLASS_OPAQUE is {}-byte H5T_OPAQUE", datatypeSize);
1601
1602            try {
1603                if (datatypeSize == NATIVE) {
1604                    datatypeNATIVE = true;
1605                    tid            = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_OPAQUE);
1606                    datatypeSize   = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_OPAQUE);
1607                }
1608                else {
1609                    datatypeNATIVE = false;
1610                    tid            = H5.H5Tcreate(HDF5Constants.H5T_OPAQUE, datatypeSize);
1611                }
1612
1613                if (opaqueTag != null) {
1614                    H5.H5Tset_tag(tid, opaqueTag);
1615                }
1616            }
1617            catch (Exception ex) {
1618                log.debug("createNative(): native opaque datatype creation failed: ", ex);
1619                if (tid >= 0)
1620                    close(tid);
1621                tid = HDF5Constants.H5I_INVALID_HID;
1622            }
1623
1624            break;
1625        default:
1626            log.debug("createNative(): Unknown class");
1627            break;
1628        } // (tclass)
1629
1630        // set up enum members
1631        if ((datatypeClass == CLASS_ENUM) && (enumMembers != null)) {
1632            log.trace("createNative(): set up enum members");
1633            try {
1634                String memstr;
1635                String memname;
1636                byte[] memval = null;
1637
1638                Iterator entries = enumMembers.entrySet().iterator();
1639                while (entries.hasNext()) {
1640                    Entry thisEntry = (Entry)entries.next();
1641                    memstr          = (String)thisEntry.getKey();
1642                    memname         = (String)thisEntry.getValue();
1643
1644                    if (datatypeSize == 1) {
1645                        log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT8");
1646                        Byte tval = Byte.parseByte(memstr);
1647                        memval    = HDFNativeData.byteToByte(tval);
1648                    }
1649                    else if (datatypeSize == 2) {
1650                        log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT16");
1651                        Short tval = Short.parseShort(memstr);
1652                        memval     = HDFNativeData.shortToByte(tval);
1653                    }
1654                    else if (datatypeSize == 4) {
1655                        log.trace("createNative(): CLASS_ENUM is H5T_NATIVE_INT32");
1656                        Integer tval = Integer.parseInt(memstr);
1657                        memval       = HDFNativeData.intToByte(tval);
1658                    }
1659                    else if (datatypeSize == 8) {
1660                        log.trace("createNative(): CLASS_INT-ENUM is H5T_NATIVE_INT64");
1661                        Long tval = Long.parseLong(memstr);
1662                        memval    = HDFNativeData.longToByte(tval);
1663                    }
1664                    else {
1665                        log.debug("createNative(): enum datatypeSize incorrect");
1666                    }
1667                    log.trace("createNative(): H5Tenum_insert {} {}", memname, memval);
1668                    H5.H5Tenum_insert(tid, memname, memval);
1669                }
1670            }
1671            catch (Exception ex) {
1672                log.debug("createNative(): set up enum members failure: ", ex);
1673            }
1674        } // (datatypeClass == CLASS_ENUM)
1675
1676        try {
1677            tmptid = tid;
1678            tid    = H5.H5Tget_native_type(tmptid);
1679        }
1680        catch (HDF5Exception ex) {
1681            log.debug("createNative(): H5Tget_native_type({}) failure: ", tmptid, ex);
1682        }
1683        finally {
1684            close(tmptid);
1685        }
1686
1687        return tid;
1688    }
1689
1690    /**
1691     * Allocates a one-dimensional array of byte, short, int, long, float, double, or String to store data in
1692     * memory. For example,
1693     *
1694     * <pre>
1695     * long tid = H5.H5Tcopy(HDF5Constants.H5T_NATIVE_INT32);
1696     * int[] data = (int[]) H5Datatype.allocateArray(datatype, 100);
1697     * </pre>
1698     *
1699     * returns a 32-bit integer array of size 100.
1700     *
1701     * @param dtype
1702     *                  the type.
1703     * @param numPoints
1704     *                  the total number of data points of the array.
1705     * @return the array object if successful; otherwise, return null.
1706     * @throws OutOfMemoryError
1707     *                          If there is a failure.
1708     */
1709    public static final Object allocateArray(final H5Datatype dtype, int numPoints) throws OutOfMemoryError
1710    {
1711        log.trace("allocateArray(): start: numPoints={}", numPoints);
1712
1713        Object data         = null;
1714        H5Datatype baseType = (H5Datatype)dtype.getDatatypeBase();
1715        int typeClass       = dtype.getDatatypeClass();
1716        long typeSize       = dtype.getDatatypeSize();
1717
1718        if (numPoints < 0) {
1719            log.debug("allocateArray(): numPoints < 0");
1720            return null;
1721        }
1722
1723        // Scalar members have dimensionality zero, i.e. size =0
1724        // what can we do about it, set the size to 1
1725        if (numPoints == 0)
1726            numPoints = 1;
1727
1728        log.trace("allocateArray(): tclass={} : tsize={}", typeClass, typeSize);
1729
1730        if (dtype.isVarStr()) {
1731            log.trace("allocateArray(): is_variable_str={}", dtype.isVarStr());
1732
1733            data = new String[numPoints];
1734            for (int i = 0; i < numPoints; i++)
1735                ((String[])data)[i] = "";
1736        }
1737        else if (typeClass == HDF5Constants.H5T_INTEGER) {
1738            log.trace("allocateArray(): class H5T_INTEGER");
1739            if (typeSize == NATIVE)
1740                typeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT);
1741
1742            switch ((int)typeSize) {
1743            case 1:
1744                data = new byte[numPoints];
1745                break;
1746            case 2:
1747                data = new short[numPoints];
1748                break;
1749            case 4:
1750                data = new int[numPoints];
1751                break;
1752            case 8:
1753                data = new long[numPoints];
1754                break;
1755            default:
1756                break;
1757            }
1758        }
1759        else if (typeClass == HDF5Constants.H5T_ENUM) {
1760            log.trace("allocateArray(): class H5T_ENUM");
1761
1762            if (baseType != null)
1763                data = H5Datatype.allocateArray(baseType, numPoints);
1764            else {
1765                if (typeSize == NATIVE)
1766                    typeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_INT);
1767                data = new byte[(int)(numPoints * typeSize)];
1768            }
1769        }
1770        else if (typeClass == HDF5Constants.H5T_COMPOUND) {
1771            log.trace("allocateArray(): class H5T_COMPOUND");
1772
1773            data = new ArrayList<>(dtype.getCompoundMemberTypes().size());
1774        }
1775        else if (typeClass == HDF5Constants.H5T_FLOAT) {
1776            log.trace("allocateArray(): class H5T_FLOAT");
1777            if (typeSize == NATIVE)
1778                typeSize = H5.H5Tget_size(HDF5Constants.H5T_NATIVE_FLOAT);
1779
1780            switch ((int)typeSize) {
1781            case 4:
1782                data = new float[numPoints];
1783                break;
1784            case 8:
1785                data = new double[numPoints];
1786                break;
1787            case 16:
1788                data = new byte[numPoints * 16];
1789                break;
1790            default:
1791                break;
1792            }
1793        }
1794        else if ((typeClass == HDF5Constants.H5T_STRING) || (typeClass == HDF5Constants.H5T_REFERENCE)) {
1795            log.trace("allocateArray(): class H5T_STRING || H5T_REFERENCE");
1796
1797            data = new byte[(int)(numPoints * typeSize)];
1798        }
1799        else if (dtype.isVLEN()) {
1800            log.trace("allocateArray(): isVLEN");
1801
1802            data = new ArrayList[numPoints];
1803            for (int j = 0; j < numPoints; j++)
1804                ((ArrayList[])data)[j] = new ArrayList<byte[]>();
1805            // if (baseType != null)
1806            // ((ArrayList<>)data).add(H5Datatype.allocateArray(baseType, numPoints));
1807        }
1808        else if (typeClass == HDF5Constants.H5T_ARRAY) {
1809            log.trace("allocateArray(): class H5T_ARRAY");
1810
1811            try {
1812                log.trace("allocateArray(): ArrayRank={}", dtype.getArrayDims().length);
1813
1814                // Use the base datatype to define the array
1815                long[] arrayDims = dtype.getArrayDims();
1816                int asize        = numPoints;
1817                for (int j = 0; j < arrayDims.length; j++) {
1818                    log.trace("allocateArray(): Array dims[{}]={}", j, arrayDims[j]);
1819
1820                    asize *= arrayDims[j];
1821                }
1822
1823                if (baseType != null)
1824                    data = H5Datatype.allocateArray(baseType, asize);
1825            }
1826            catch (Exception ex) {
1827                log.debug("allocateArray(): H5T_ARRAY class failure: ", ex);
1828            }
1829        }
1830        else if ((typeClass == HDF5Constants.H5T_OPAQUE) || (typeClass == HDF5Constants.H5T_BITFIELD)) {
1831            log.trace("allocateArray(): class H5T_OPAQUE || H5T_BITFIELD");
1832            if (typeSize == NATIVE)
1833                typeSize = H5.H5Tget_size(typeClass);
1834
1835            data = new byte[(int)(numPoints * typeSize)];
1836        }
1837        else {
1838            log.debug("allocateArray(): class ???? ({})", typeClass);
1839
1840            data = null;
1841        }
1842
1843        return data;
1844    }
1845
1846    /**
1847     * Returns the size (in bytes) of a given datatype identifier. It basically just calls H5Tget_size(tid).
1848     *
1849     * @param tid
1850     *            The datatype identifier.
1851     * @return The size of the datatype in bytes.
1852     * @see hdf.hdf5lib.H5#H5Tget_size(long)
1853     */
1854    public static final long getDatatypeSize(long tid)
1855    {
1856        // data type information
1857        long tsize = -1;
1858
1859        try {
1860            tsize = H5.H5Tget_size(tid);
1861        }
1862        catch (Exception ex) {
1863            tsize = -1;
1864        }
1865
1866        return tsize;
1867    }
1868
1869    /*
1870     * (non-Javadoc)
1871     * @see hdf.object.Datatype#getDescription()
1872     */
1873    @Override
1874    public String getDescription()
1875    {
1876        log.trace("getDescription(): start - isNamed={}", isNamed());
1877
1878        if (datatypeDescription != null)
1879            return datatypeDescription;
1880
1881        StringBuilder description = new StringBuilder();
1882        long tid                  = HDF5Constants.H5I_INVALID_HID;
1883
1884        switch (datatypeClass) {
1885        case CLASS_CHAR:
1886            log.trace("getDescription(): Char");
1887            description.append("8-bit ").append(isUnsigned() ? "unsigned " : "").append("integer");
1888            break;
1889        case CLASS_INTEGER:
1890            log.trace("getDescription(): Int [{}]", datatypeNATIVE);
1891            if (datatypeNATIVE)
1892                description.append("native ").append(isUnsigned() ? "unsigned " : "").append("integer");
1893            else
1894                description.append(String.valueOf(datatypeSize * 8))
1895                    .append("-bit ")
1896                    .append(isUnsigned() ? "unsigned " : "")
1897                    .append("integer");
1898            break;
1899        case CLASS_FLOAT:
1900            log.trace("getDescription(): Float");
1901            if (datatypeNATIVE)
1902                description.append("native floating-point");
1903            else
1904                description.append(String.valueOf(datatypeSize * 8)).append("-bit floating-point");
1905            break;
1906        case CLASS_STRING:
1907            log.trace("getDescription(): String");
1908            description.append("String, length = ").append(isVarStr() ? "variable" : datatypeSize);
1909
1910            try {
1911                tid = createNative();
1912                if (tid >= 0) {
1913                    String strPadType;
1914                    String strCSETType;
1915                    int strPad  = H5.H5Tget_strpad(tid);
1916                    int strCSET = H5.H5Tget_cset(tid);
1917
1918                    if (strPad == HDF5Constants.H5T_STR_NULLTERM)
1919                        strPadType = "H5T_STR_NULLTERM";
1920                    else if (strPad == HDF5Constants.H5T_STR_NULLPAD)
1921                        strPadType = "H5T_STR_NULLPAD";
1922                    else if (strPad == HDF5Constants.H5T_STR_SPACEPAD)
1923                        strPadType = "H5T_STR_SPACEPAD";
1924                    else
1925                        strPadType = null;
1926
1927                    if (strPadType != null)
1928                        description.append(", padding = ").append(strPadType);
1929
1930                    if (strCSET == HDF5Constants.H5T_CSET_ASCII)
1931                        strCSETType = "H5T_CSET_ASCII";
1932                    else if (strCSET == HDF5Constants.H5T_CSET_UTF8)
1933                        strCSETType = "H5T_CSET_UTF8";
1934                    else
1935                        strCSETType = null;
1936
1937                    if (strCSETType != null)
1938                        description.append(", cset = ").append(strCSETType);
1939                }
1940                else {
1941                    log.debug("createNative() failure");
1942                }
1943            }
1944            catch (Exception ex) {
1945                log.debug("H5Tget_strpad failure: ", ex);
1946            }
1947            finally {
1948                close(tid);
1949            }
1950            break;
1951        case CLASS_BITFIELD:
1952            log.trace("getDescription(): Bit");
1953            if (datatypeNATIVE)
1954                description.append("native bitfield");
1955            else
1956                description.append(String.valueOf(datatypeSize * 8)).append("-bit bitfield");
1957            break;
1958        case CLASS_OPAQUE:
1959            log.trace("getDescription(): Opaque");
1960            if (datatypeNATIVE)
1961                description.append("native Opaque");
1962            else
1963                description.append(String.valueOf(datatypeSize)).append("-byte Opaque");
1964
1965            if (opaqueTag != null) {
1966                description.append(", tag = ").append(opaqueTag);
1967            }
1968
1969            break;
1970        case CLASS_COMPOUND:
1971            log.trace("getDescription(): Compound");
1972            description.append("Compound");
1973
1974            if ((compoundMemberTypes != null) && !compoundMemberTypes.isEmpty()) {
1975                Iterator<String> memberNames   = null;
1976                Iterator<Datatype> memberTypes = compoundMemberTypes.iterator();
1977
1978                if (compoundMemberNames != null)
1979                    memberNames = compoundMemberNames.iterator();
1980
1981                description.append(" {");
1982
1983                while (memberTypes.hasNext()) {
1984                    if (memberNames != null && memberNames.hasNext()) {
1985                        description.append(memberNames.next()).append(" = ");
1986                    }
1987
1988                    description.append(memberTypes.next().getDescription());
1989
1990                    if (memberTypes.hasNext())
1991                        description.append(", ");
1992                }
1993
1994                description.append("}");
1995            }
1996
1997            break;
1998        case CLASS_REFERENCE:
1999            log.trace("getDescription(): Ref");
2000            description.append("Reference");
2001
2002            try {
2003                boolean isRegionType = false;
2004
2005                tid = createNative();
2006                if (tid >= 0) {
2007                    if (!H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF)) {
2008                        isRegionType = H5.H5Tequal(tid, HDF5Constants.H5T_STD_REF_DSETREG);
2009
2010                        description.setLength(0);
2011                        if (isRegionType) {
2012                            description.append("Dataset region reference");
2013                        }
2014                        else {
2015                            description.append("Object reference");
2016                        }
2017                    }
2018                }
2019            }
2020            catch (Exception ex) {
2021                log.debug("H5.H5Tequal failure: ", ex);
2022            }
2023            finally {
2024                close(tid);
2025            }
2026
2027            break;
2028        case CLASS_ENUM:
2029            log.trace("getDescription(): Enum");
2030            if (datatypeNATIVE)
2031                description.append("native enum");
2032            else
2033                description.append(String.valueOf(datatypeSize * 8)).append("-bit enum");
2034
2035            String members = getEnumMembersAsString();
2036            if (members != null)
2037                description.append(" (").append(members).append(")");
2038
2039            break;
2040        case CLASS_VLEN:
2041            log.trace("getDescription(): Var Len");
2042            description.append("Variable-length");
2043
2044            if (baseType != null)
2045                description.append(" of ").append(baseType.getDescription());
2046
2047            break;
2048        case CLASS_ARRAY:
2049            log.trace("getDescription(): Array");
2050            description.append("Array");
2051
2052            if (arrayDims != null) {
2053                description.append(" [");
2054                for (int i = 0; i < arrayDims.length; i++) {
2055                    description.append(arrayDims[i]);
2056                    if (i < arrayDims.length - 1)
2057                        description.append(" x ");
2058                }
2059                description.append("]");
2060            }
2061
2062            if (baseType != null)
2063                description.append(" of ").append(baseType.getDescription());
2064
2065            break;
2066        default:
2067            description.append("Unknown");
2068            break;
2069        }
2070        if (isNamed())
2071            description.append("->").append(getFullName());
2072
2073        return description.toString();
2074    }
2075
2076    /**
2077     * Checks if a datatype specified by the identifier is an unsigned integer.
2078     *
2079     * @param tid
2080     *            the datatype ID to be checked.
2081     * @return true is the datatype is an unsigned integer; otherwise returns false.
2082     */
2083    public static final boolean isUnsigned(long tid)
2084    {
2085        boolean unsigned = false;
2086
2087        if (tid >= 0) {
2088            try {
2089                int tclass = H5.H5Tget_class(tid);
2090                log.trace("isUnsigned(): tclass = {}", tclass);
2091                if (tclass != HDF5Constants.H5T_FLOAT && tclass != HDF5Constants.H5T_STRING &&
2092                    tclass != HDF5Constants.H5T_REFERENCE && tclass != HDF5Constants.H5T_BITFIELD &&
2093                    tclass != HDF5Constants.H5T_OPAQUE && tclass != HDF5Constants.H5T_VLEN &&
2094                    tclass != HDF5Constants.H5T_COMPOUND && tclass != HDF5Constants.H5T_ARRAY) {
2095                    int tsign = H5.H5Tget_sign(tid);
2096                    if (tsign == HDF5Constants.H5T_SGN_NONE)
2097                        unsigned = true;
2098                    else
2099                        log.trace("isUnsigned(): not unsigned");
2100                }
2101                else {
2102                    log.trace("isUnsigned(): tclass not integer type");
2103                }
2104            }
2105            catch (Exception ex) {
2106                log.debug("isUnsigned(): Datatype {} failure", tid, ex);
2107                unsigned = false;
2108            }
2109        }
2110        else {
2111            log.trace("isUnsigned(): not a valid datatype");
2112        }
2113
2114        return unsigned;
2115    }
2116
2117    /**
2118     * Removes all of the elements from metadata list. The list should be empty after this call returns.
2119     */
2120    @Override
2121    public void clear()
2122    {
2123        super.clear();
2124        objMetadata.clear();
2125    }
2126
2127    /**
2128     * Retrieves the object's metadata, such as attributes, from the file. Metadata, such as attributes, is
2129     * stored in a List.
2130     *
2131     * @return the list of metadata objects.
2132     * @throws HDF5Exception
2133     *                       if the metadata can not be retrieved
2134     */
2135    @Override
2136    public List<Attribute> getMetadata() throws HDF5Exception
2137    {
2138        int gmIndexType  = 0;
2139        int gmIndexOrder = 0;
2140
2141        try {
2142            gmIndexType = fileFormat.getIndexType(null);
2143        }
2144        catch (Exception ex) {
2145            log.debug("getMetadata(): getIndexType failed: ", ex);
2146        }
2147        try {
2148            gmIndexOrder = fileFormat.getIndexOrder(null);
2149        }
2150        catch (Exception ex) {
2151            log.debug("getMetadata(): getIndexOrder failed: ", ex);
2152        }
2153        return this.getMetadata(gmIndexType, gmIndexOrder);
2154    }
2155
2156    /**
2157     * Retrieves the object's metadata, such as attributes, from the file. Metadata, such as attributes, is
2158     * stored in a List.
2159     *
2160     * @param attrPropList
2161     *                     the list of properties to get
2162     * @return the list of metadata objects.
2163     * @throws HDF5Exception
2164     *                       if the metadata can not be retrieved
2165     */
2166    public List<Attribute> getMetadata(int... attrPropList) throws HDF5Exception
2167    {
2168        try {
2169            this.linkTargetObjName = H5File.getLinkTargetName(this);
2170        }
2171        catch (Exception ex) {
2172            log.debug("getMetadata(): getLinkTargetName failed: ", ex);
2173        }
2174
2175        List<Attribute> attrlist = null;
2176        try {
2177            attrlist = objMetadata.getMetadata(attrPropList);
2178        }
2179        catch (Exception ex) {
2180            log.debug("getMetadata(): getMetadata failed: ", ex);
2181        }
2182        return attrlist;
2183    }
2184
2185    /**
2186     * Writes a specific piece of metadata (such as an attribute) into the file. If an HDF(4&amp;5) attribute
2187     * exists in the file, this method updates its value. If the attribute does not exist in the file, it
2188     * creates the attribute in the file and attaches it to the object. It will fail to write a new attribute
2189     * to the object where an attribute with the same name already exists. To update the value of an existing
2190     * attribute in the file, one needs to get the instance of the attribute by getMetadata(), change its
2191     * values, then use writeMetadata() to write the value.
2192     *
2193     * @param info
2194     *             the metadata to write.
2195     * @throws Exception
2196     *                   if the metadata can not be written
2197     */
2198    @Override
2199    public void writeMetadata(Object info) throws Exception
2200    {
2201        try {
2202            objMetadata.writeMetadata(info);
2203        }
2204        catch (Exception ex) {
2205            log.debug("writeMetadata(): Object not an Attribute");
2206        }
2207    }
2208
2209    /**
2210     * Deletes an existing piece of metadata from this object.
2211     *
2212     * @param info
2213     *             the metadata to delete.
2214     * @throws HDF5Exception
2215     *                       if the metadata can not be removed
2216     */
2217    @Override
2218    public void removeMetadata(Object info) throws HDF5Exception
2219    {
2220        try {
2221            objMetadata.removeMetadata(info);
2222        }
2223        catch (Exception ex) {
2224            log.debug("removeMetadata(): Object not an Attribute");
2225            return;
2226        }
2227
2228        Attribute attr = (Attribute)info;
2229        log.trace("removeMetadata(): {}", attr.getAttributeName());
2230        long tid = open();
2231        if (tid >= 0) {
2232            try {
2233                H5.H5Adelete(tid, attr.getAttributeName());
2234            }
2235            catch (Exception ex) {
2236                log.debug("removeMetadata(): ", ex);
2237            }
2238            finally {
2239                close(tid);
2240            }
2241        }
2242        else {
2243            log.debug("removeMetadata(): failed to open datatype");
2244        }
2245    }
2246
2247    /**
2248     * Updates an existing piece of metadata attached to this object.
2249     *
2250     * @param info
2251     *             the metadata to update.
2252     * @throws HDF5Exception
2253     *                       if the metadata can not be updated
2254     */
2255    @Override
2256    public void updateMetadata(Object info) throws HDF5Exception
2257    {
2258        try {
2259            objMetadata.updateMetadata(info);
2260        }
2261        catch (Exception ex) {
2262            log.debug("updateMetadata(): Object not an Attribute");
2263            return;
2264        }
2265    }
2266
2267    /*
2268     * (non-Javadoc)
2269     * @see hdf.object.HObject#setName(java.lang.String)
2270     */
2271    @Override
2272    public void setName(String newName) throws Exception
2273    {
2274        if (newName == null)
2275            throw new IllegalArgumentException("The new name is NULL");
2276
2277        H5File.renameObject(this, newName);
2278        super.setName(newName);
2279    }
2280
2281    @Override
2282    public void setFullname(String newPath, String newName) throws Exception
2283    {
2284        H5File.renameObject(this, newPath, newName);
2285        super.setFullname(newPath, newName);
2286    }
2287
2288    @Override
2289    public boolean isText()
2290    {
2291        return (datatypeClass == Datatype.CLASS_STRING);
2292    }
2293
2294    /**
2295     * Checks if this datatype is an object reference type.
2296     *
2297     * @return true if the datatype is an object reference; false otherwise
2298     */
2299    public boolean isRefObj() { return isRefObj; }
2300
2301    /**
2302     * Checks if this datatype is a region reference type.
2303     *
2304     * @return true if the datatype is a region reference; false otherwise
2305     */
2306    public boolean isRegRef() { return isRegRef; }
2307
2308    /**
2309     * Checks if this datatype is a standard reference type.
2310     *
2311     * @return true if the datatype is a standard reference; false otherwise
2312     */
2313    public boolean isStdRef() { return isStdRef; }
2314
2315    /*
2316     * (non-Javadoc)
2317     * @see hdf.object.Datatype#getReferenceType()
2318     */
2319    @Override
2320    public long getReferenceType() throws HDF5Exception
2321    {
2322        if (isRegRef)
2323            return HDF5Constants.H5T_STD_REF_DSETREG;
2324        if (isRefObj)
2325            return HDF5Constants.H5T_STD_REF_OBJ;
2326        if (isStdRef)
2327            return HDF5Constants.H5T_STD_REF;
2328        return -1;
2329    }
2330
2331    /**
2332     * Describes the dataset object description for a 1.10 reference.
2333     *
2334     * @param container
2335     *                  the dataset/attribute with the reference
2336     * @param refarr
2337     *                  the reference datatype data to be checked.
2338     *
2339     * @return the dataset reference object description.
2340     */
2341    public static String descReferenceObject(long container, byte[] refarr)
2342    {
2343        String region_desc = H5.H5Rget_name_string(container, HDF5Constants.H5R_OBJECT, refarr);
2344        region_desc += " H5O_TYPE_OBJ_REF";
2345        log.trace("descReferenceObject region_desc={}:", region_desc);
2346        return region_desc;
2347    }
2348
2349    /**
2350     * Describes the dataset region description for a 1.10 reference.
2351     *
2352     * @param container
2353     *                  the dataset/attribute with the reference
2354     * @param refarr
2355     *                  the reference datatype data to be checked.
2356     *
2357     * @return the dataset region description.
2358     */
2359    public static String descRegionDataset(long container, byte[] refarr)
2360    {
2361        String region_desc = H5.H5Rget_name_string(container, HDF5Constants.H5R_DATASET_REGION, refarr);
2362        log.trace("descRegionDataset region_desc={}:", region_desc);
2363        long new_obj_id = HDF5Constants.H5I_INVALID_HID;
2364        try {
2365            log.trace("descRegionDataset refarr2={}:", refarr);
2366            new_obj_id       = H5.H5Rdereference(container, HDF5Constants.H5P_DEFAULT,
2367                                                 HDF5Constants.H5R_DATASET_REGION, refarr);
2368            long new_obj_sid = HDF5Constants.H5I_INVALID_HID;
2369            try {
2370                log.trace("descRegionDataset refarr3={}:", refarr);
2371                new_obj_sid = H5.H5Rget_region(container, HDF5Constants.H5R_DATASET_REGION, refarr);
2372                try {
2373                    int region_type = H5.H5Sget_select_type(new_obj_sid);
2374                    log.debug("descRegionDataset Reference Region Type {}", region_type);
2375                    long reg_ndims   = H5.H5Sget_simple_extent_ndims(new_obj_sid);
2376                    StringBuilder sb = new StringBuilder();
2377                    if (HDF5Constants.H5S_SEL_POINTS == region_type) {
2378                        sb.append(" REGION_TYPE POINT ");
2379                        long reg_npoints = H5.H5Sget_select_elem_npoints(new_obj_sid);
2380                        long getcoord[]  = new long[(int)(reg_ndims * reg_npoints)];
2381                        try {
2382                            H5.H5Sget_select_elem_pointlist(new_obj_sid, 0, reg_npoints, getcoord);
2383                        }
2384                        catch (Exception ex5) {
2385                            log.debug("descRegionDataset H5.H5Sget_select_elem_pointlist: ", ex5);
2386                        }
2387                        sb.append("{ ");
2388                        for (int i = 0; i < (int)reg_npoints; i++) {
2389                            if (i > 0)
2390                                sb.append(" ");
2391                            sb.append("(");
2392                            for (int j = 0; j < (int)reg_ndims; j++) {
2393                                if (j > 0)
2394                                    sb.append(",");
2395                                sb.append(getcoord[i * (int)reg_ndims + j]);
2396                            }
2397                            sb.append(")");
2398                        }
2399                        sb.append(" }");
2400                        region_desc += sb.toString();
2401                    }
2402                    else if (HDF5Constants.H5S_SEL_HYPERSLABS == region_type) {
2403                        sb.append(" REGION_TYPE BLOCK ");
2404                        long reg_nblocks = H5.H5Sget_select_hyper_nblocks(new_obj_sid);
2405                        long getblocks[] = new long[(int)(reg_ndims * reg_nblocks) * 2];
2406                        try {
2407                            H5.H5Sget_select_hyper_blocklist(new_obj_sid, 0, reg_nblocks, getblocks);
2408                        }
2409                        catch (Exception ex5) {
2410                            log.debug("descRegionDataset H5.H5Sget_select_hyper_blocklist: ", ex5);
2411                        }
2412                        sb.append("{ ");
2413                        for (int i = 0; i < (int)reg_nblocks; i++) {
2414                            if (i > 0)
2415                                sb.append(" ");
2416                            sb.append("(");
2417                            for (int j = 0; j < (int)reg_ndims; j++) {
2418                                if (j > 0)
2419                                    sb.append(",");
2420                                sb.append(getblocks[i * 2 * (int)reg_ndims + j]);
2421                            }
2422                            sb.append(")-(");
2423                            for (int j = 0; j < (int)reg_ndims; j++) {
2424                                if (j > 0)
2425                                    sb.append(",");
2426                                sb.append(getblocks[i * 2 * (int)reg_ndims + (int)reg_ndims + j]);
2427                            }
2428                            sb.append(")");
2429                        }
2430                        sb.append(" }");
2431                        region_desc += sb.toString();
2432                    }
2433                    else
2434                        region_desc += " REGION_TYPE UNKNOWN";
2435                }
2436                catch (Exception ex4) {
2437                    log.debug("descRegionDataset Region Type", ex4);
2438                }
2439            }
2440            catch (Exception ex3) {
2441                log.debug("descRegionDataset Space Open", ex3);
2442            }
2443            finally {
2444                H5.H5Sclose(new_obj_sid);
2445            }
2446            log.trace("descRegionDataset finish");
2447        }
2448        catch (Exception ex2) {
2449            log.debug("descRegionDataset ", ex2);
2450        }
2451        finally {
2452            H5.H5Dclose(new_obj_id);
2453        }
2454        return region_desc;
2455    }
2456
2457    /**
2458     * Gets the dataset reference type for a 1.10 reference.
2459     *
2460     * @param container
2461     *                  the dataset/attribute with the reference
2462     * @param refarr
2463     *                  the reference datatype data to be checked.
2464     *
2465     * @return the dataset reference type.
2466     */
2467    public static int typeObjectRef(long container, int obj_type, byte[] refarr)
2468    {
2469        int ref_type    = -1;
2470        long new_obj_id = HDF5Constants.H5I_INVALID_HID;
2471        try {
2472            log.trace("typeObjectRef refarr2={}:", refarr);
2473            new_obj_id = H5.H5Rdereference(container, HDF5Constants.H5P_DEFAULT, obj_type, refarr);
2474            if (HDF5Constants.H5R_DATASET_REGION == obj_type) {
2475                long new_obj_sid = HDF5Constants.H5I_INVALID_HID;
2476                try {
2477                    log.trace("typeObjectRef refarr3={}:", refarr);
2478                    new_obj_sid = H5.H5Rget_region(container, HDF5Constants.H5R_DATASET_REGION, refarr);
2479                    try {
2480                        ref_type = H5.H5Sget_select_type(new_obj_sid);
2481                        log.debug("typeObjectRef Reference Region Type {}", ref_type);
2482                    }
2483                    catch (Exception ex4) {
2484                        log.debug("typeObjectRef Region Type", ex4);
2485                    }
2486                }
2487                catch (Exception ex3) {
2488                    log.debug("typeObjectRef Space Open", ex3);
2489                }
2490                finally {
2491                    H5.H5Sclose(new_obj_sid);
2492                }
2493            }
2494            else {
2495                H5O_info_t objInfo;
2496
2497                objInfo  = H5.H5Oget_info(new_obj_id);
2498                ref_type = objInfo.type;
2499            }
2500            log.trace("typeObjectRef finish");
2501        }
2502        catch (Exception ex2) {
2503            log.debug("typeObjectRef ", ex2);
2504        }
2505        finally {
2506            H5.H5Dclose(new_obj_id);
2507        }
2508        return ref_type;
2509    }
2510
2511    /**
2512     * Checks if a reference datatype is all zero.
2513     *
2514     * @param refarr
2515     *               the reference datatype data to be checked.
2516     * @return true is the reference datatype data is all zero; otherwise returns false.
2517     */
2518    public static boolean zeroArrayCheck(final byte[] refarr)
2519    {
2520        for (byte b : refarr) {
2521            if (b != 0)
2522                return false;
2523        }
2524        return true;
2525    }
2526
2527    /**
2528     * Gets the string padding.
2529     *
2530     * @return the string padding value
2531     */
2532    public int getNativeStrPad() { return nativeStrPad; }
2533
2534    /**
2535     * Extracts compound information into flat structure. For example, compound datatype "nest" has {nest1{a,
2536     * b, c}, d, e} then extractCompoundInfo() will put the names of nested compound fields into a flat list
2537     * as
2538     *
2539     * <pre>
2540     * nest.nest1.a
2541     * nest.nest1.b
2542     * nest.nest1.c
2543     * nest.d
2544     * nest.e
2545     * </pre>
2546     *
2547     * @param dtype
2548     *                      the datatype to extract compound info from
2549     * @param name
2550     *                      the name of the compound datatype
2551     * @param names
2552     *                      the list to store the member names of the compound datatype
2553     * @param flatListTypes
2554     *                      the list to store the nested member names of the compound datatype
2555     */
2556    public static void extractCompoundInfo(final H5Datatype dtype, String name, List<String> names,
2557                                           List<Datatype> flatListTypes)
2558    {
2559        log.trace("extractCompoundInfo(): start: name={}", name);
2560
2561        if (dtype.isArray()) {
2562            log.trace("extractCompoundInfo(): array type - extracting compound info from base datatype");
2563            H5Datatype.extractCompoundInfo((H5Datatype)dtype.getDatatypeBase(), name, names, flatListTypes);
2564        }
2565        else if (dtype.isVLEN() && !dtype.isVarStr()) {
2566            log.trace(
2567                "extractCompoundInfo(): variable-length type - extracting compound info from base datatype");
2568            H5Datatype.extractCompoundInfo((H5Datatype)dtype.getDatatypeBase(), name, names, flatListTypes);
2569        }
2570        else if (dtype.isCompound()) {
2571            List<String> compoundMemberNames   = dtype.getCompoundMemberNames();
2572            List<Datatype> compoundMemberTypes = dtype.getCompoundMemberTypes();
2573            Datatype mtype                     = null;
2574            String mname                       = null;
2575
2576            if (compoundMemberNames == null) {
2577                log.debug("extractCompoundInfo(): compoundMemberNames is null");
2578                return;
2579            }
2580
2581            if (compoundMemberNames.isEmpty()) {
2582                log.debug("extractCompoundInfo(): compound datatype has no members");
2583                return;
2584            }
2585
2586            log.trace("extractCompoundInfo(): nMembers={}", compoundMemberNames.size());
2587
2588            for (int i = 0; i < compoundMemberNames.size(); i++) {
2589                log.trace("extractCompoundInfo(): member[{}]:", i);
2590
2591                mtype = compoundMemberTypes.get(i);
2592
2593                log.trace("extractCompoundInfo(): type={} with size={}", mtype.getDescription(),
2594                          mtype.getDatatypeSize());
2595
2596                if (names != null) {
2597                    mname = name + compoundMemberNames.get(i);
2598                    log.trace("extractCompoundInfo(): mname={}, name={}", mname, name);
2599                }
2600
2601                if (mtype.isCompound()) {
2602                    H5Datatype.extractCompoundInfo((H5Datatype)mtype, mname + CompoundDS.SEPARATOR, names,
2603                                                   flatListTypes);
2604                    log.trace("extractCompoundInfo(): continue after recursive compound");
2605                    continue;
2606                }
2607
2608                if (names != null) {
2609                    names.add(mname);
2610                }
2611
2612                flatListTypes.add(mtype);
2613
2614                /*
2615                 * For ARRAY of COMPOUND and VLEN of COMPOUND types, we first add the top-level array or vlen
2616                 * type to the list of datatypes, and then follow that with a listing of the datatypes inside
2617                 * the nested compound.
2618                 */
2619                /*
2620                 * TODO: Don't flatten variable-length types until true variable-length support is
2621                 * implemented.
2622                 */
2623                if (mtype.isArray() /* || (mtype.isVLEN() && !mtype.isVarStr()) */) {
2624                    H5Datatype.extractCompoundInfo((H5Datatype)mtype, mname + CompoundDS.SEPARATOR, names,
2625                                                   flatListTypes);
2626                }
2627            }
2628        }
2629    }
2630
2631    /**
2632     * Creates a datatype of a compound with one field. This function is needed to read/write data field by
2633     * field.
2634     *
2635     * @param memberName
2636     *                   The name of the datatype
2637     * @return the identifier of the compound datatype.
2638     * @throws HDF5Exception
2639     *                       If there is an error at the HDF5 library level.
2640     */
2641    public long createCompoundFieldType(String memberName) throws HDF5Exception
2642    {
2643        log.trace("createCompoundFieldType(): start member_name={}", memberName);
2644
2645        long topTID  = HDF5Constants.H5I_INVALID_HID;
2646        long tmpTID1 = HDF5Constants.H5I_INVALID_HID;
2647
2648        try {
2649            if (this.isArray()) {
2650                log.trace("createCompoundFieldType(): array datatype");
2651
2652                if (baseType != null) {
2653                    log.trace("createCompoundFieldType(): creating compound field type from base datatype");
2654                    tmpTID1 = ((H5Datatype)baseType).createCompoundFieldType(memberName);
2655                }
2656
2657                log.trace("createCompoundFieldType(): creating container array datatype");
2658                topTID = H5.H5Tarray_create(tmpTID1, arrayDims.length, arrayDims);
2659            }
2660            else if (this.isVLEN()) {
2661                log.trace("createCompoundFieldType(): variable-length datatype");
2662
2663                if (baseType != null) {
2664                    log.trace("createCompoundFieldType(): creating compound field type from base datatype");
2665                    tmpTID1 = ((H5Datatype)baseType).createCompoundFieldType(memberName);
2666                }
2667
2668                log.trace("createCompoundFieldType(): creating container variable-length datatype");
2669                topTID = H5.H5Tvlen_create(tmpTID1);
2670            }
2671            else if (this.isCompound()) {
2672                log.trace("createCompoundFieldType(): compound datatype");
2673
2674                String insertedName = memberName;
2675
2676                int sep = memberName.indexOf(CompoundDS.SEPARATOR);
2677                if (sep >= 0) {
2678                    /*
2679                     * If a compound separator character is present in the supplied string, then there is an
2680                     * additional level of compound nesting. We will create a compound type to hold the nested
2681                     * compound type.
2682                     */
2683                    insertedName = memberName.substring(0, sep);
2684
2685                    log.trace("createCompoundFieldType(): member with name {} is nested inside compound",
2686                              insertedName);
2687                }
2688
2689                /*
2690                 * Retrieve the index of the compound member by its name.
2691                 */
2692                int memberIndex = this.compoundMemberNames.indexOf(insertedName);
2693                if (memberIndex >= 0) {
2694                    H5Datatype memberType = (H5Datatype)this.compoundMemberTypes.get(memberIndex);
2695
2696                    log.trace("createCompoundFieldType(): Member {} is type {} of size={} with baseType={}",
2697                              insertedName, memberType.getDescription(), memberType.getDatatypeSize(),
2698                              memberType.getDatatypeBase());
2699
2700                    if (sep >= 0)
2701                        /*
2702                         * Additional compound nesting; create the nested compound type.
2703                         */
2704                        tmpTID1 = memberType.createCompoundFieldType(memberName.substring(sep + 1));
2705                    else
2706                        tmpTID1 = memberType.createNative();
2707
2708                    log.trace("createCompoundFieldType(): creating container compound datatype");
2709                    topTID = H5.H5Tcreate(HDF5Constants.H5T_COMPOUND, datatypeSize);
2710
2711                    log.trace("createCompoundFieldType(): inserting member {} into compound datatype",
2712                              insertedName);
2713                    H5.H5Tinsert(topTID, insertedName, 0, tmpTID1);
2714
2715                    /*
2716                     * WARNING!!! This step is crucial. Without it, the compound type created might be larger
2717                     * than the size of the single datatype field we are inserting. Performing a read with a
2718                     * compound datatype of an incorrect size will corrupt JVM memory and cause strange
2719                     * behavior and crashes.
2720                     */
2721                    H5.H5Tpack(topTID);
2722                }
2723                else {
2724                    log.debug(
2725                        "createCompoundFieldType(): member name {} not found in compound datatype's member name list",
2726                        memberName);
2727                }
2728            }
2729        }
2730        catch (Exception ex) {
2731            log.debug("createCompoundFieldType(): creation of compound field type failed: ", ex);
2732            topTID = HDF5Constants.H5I_INVALID_HID;
2733        }
2734        finally {
2735            close(tmpTID1);
2736        }
2737
2738        return topTID;
2739    }
2740
2741    private boolean datatypeIsComplex(long tid)
2742    {
2743        long tclass = HDF5Constants.H5T_NO_CLASS;
2744
2745        try {
2746            tclass = H5.H5Tget_class(tid);
2747            log.trace("datatypeIsComplex():{}", tclass);
2748        }
2749        catch (Exception ex) {
2750            log.debug("datatypeIsComplex():", ex);
2751        }
2752
2753        boolean retVal = (tclass == HDF5Constants.H5T_COMPOUND);
2754        retVal |= (tclass == HDF5Constants.H5T_ENUM);
2755        retVal |= (tclass == HDF5Constants.H5T_VLEN);
2756        retVal |= (tclass == HDF5Constants.H5T_ARRAY);
2757
2758        return retVal;
2759    }
2760
2761    private boolean datatypeIsReference(long tid)
2762    {
2763        long tclass = HDF5Constants.H5T_NO_CLASS;
2764
2765        try {
2766            tclass = H5.H5Tget_class(tid);
2767            log.trace("datatypeIsReference():{}", tclass);
2768        }
2769        catch (Exception ex) {
2770            log.debug("datatypeIsReference():", ex);
2771        }
2772
2773        return (tclass == HDF5Constants.H5T_REFERENCE);
2774    }
2775
2776    private boolean datatypeIsAtomic(long tid)
2777    {
2778        boolean retVal = !(datatypeIsComplex(tid) | datatypeIsReference(tid) | isRef());
2779        retVal |= isOpaque();
2780        retVal |= isBitField();
2781
2782        return retVal;
2783    }
2784
2785    private boolean datatypeClassIsComplex(long tclass)
2786    {
2787        boolean retVal = (tclass == HDF5Constants.H5T_COMPOUND);
2788        retVal |= (tclass == HDF5Constants.H5T_ENUM);
2789        retVal |= (tclass == HDF5Constants.H5T_VLEN);
2790        retVal |= (tclass == HDF5Constants.H5T_ARRAY);
2791
2792        return retVal;
2793    }
2794
2795    private boolean datatypeClassIsReference(long tclass) { return (tclass == HDF5Constants.H5T_REFERENCE); }
2796
2797    private boolean datatypeClassIsOpaque(long tclass) { return (tclass == Datatype.CLASS_OPAQUE); }
2798
2799    private boolean datatypeClassIsAtomic(long tclass)
2800    {
2801        boolean retVal = !(datatypeClassIsComplex(tclass) | datatypeClassIsReference(tclass));
2802        retVal |= (tclass == Datatype.CLASS_OPAQUE);
2803        retVal |= (tclass == Datatype.CLASS_BITFIELD);
2804
2805        return retVal;
2806    }
2807}