    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;
    018
    019import java.util.ArrayList;
    020import java.util.Arrays;
    021import java.util.Collection;
    022import java.util.HashMap;
    023import java.util.Iterator;
    024import java.util.List;
    025import java.util.Map;
    026import java.util.Vector;
    027import java.util.regex.Pattern;
    028
    029import org.slf4j.Logger;
    030import org.slf4j.LoggerFactory;
    031
    032import hdf.hdf5lib.H5;
    033import hdf.hdf5lib.HDF5Constants;
    034import hdf.hdf5lib.structs.H5O_info_t;
    035
    036import hdf.object.Datatype;
    037import hdf.object.FileFormat;
    038
    039/**
    040 * This class defines HDF5 reference characteristics and APIs for a data type of H5T_STD_REF.
    041 *
    042 * This class provides convenient functions to access H5T_STD_REF type information.
    043 */
    044public class H5ReferenceType extends H5Datatype
    045{
    046    private static final long serialVersionUID    = -3360885430038261178L;
    047
    048    private static final Logger log = LoggerFactory.getLogger(H5ReferenceType.class);
    049
    050    /**
    051     * The memory buffer that holds the raw data array of the reference.
    052     */
    053    protected transient ArrayList<H5ReferenceData> refdata;
    054
    055    /** Flag to indicate if data values are loaded into memory. */
    056    protected boolean         isDataLoaded = false;
    057
    058    /** Flag to indicate if this dataset has been initialized */
    059    protected boolean         inited = false;
    060
    061    /** The current array size of the reference. */
    062    protected long            refsize;
    063
    064    /**
    065     * The data buffer that contains the raw data directly reading from file
    066     * (before any data conversion).
    067     */
    068    protected transient Object originalRefBuf = null;
    069
    070    /**
    071     * Constructs an named HDF5 data type reference for a given file, dataset name and group path.
    072     *
    073     * The datatype object represents an existing named datatype in file. For example,
    074     *
    075     * <pre>
    076     * new H5ReferenceType(file, "dset1", "/g0")
    077     * </pre>
    078     *
    079     * constructs a datatype object that corresponds to the dataset,"dset1", at group "/g0".
    080     *
    081     * @param theFile
    082     *            the file that contains the datatype.
    083     * @param theName
    084     *            the name of the dataset such as "dset1".
    085     * @param thePath
    086     *            the group path to the dataset such as "/g0/".
    087     */
    088    public H5ReferenceType(FileFormat theFile, String theName, String thePath) {
    089        this(theFile, theName, thePath, null);
    090    }
    091
    092    /**
    093     * @deprecated Not for public use in the future. <br>
    094     *             Using {@link #H5ReferenceType(FileFormat, String, String)}
    095     *
    096     * @param theFile
    097     *            the file that contains the datatype.
    098     * @param theName
    099     *            the name of the dataset such as "dset1".
    100     * @param thePath
    101     *            the group path to the dataset such as "/g0/".
    102     * @param oid
    103     *            the oid of the dataset.
    104     */
    105    @Deprecated
    106    public H5ReferenceType(FileFormat theFile, String theName, String thePath, long[] oid) {
    107        super(theFile, theName, thePath, oid);
    108
    109        log.trace("constructor theName {}", theName);
    110        refdata = null;
    111     }
    112
    113    /**
    114     * Constructs a H5ReferenceType with specified class, size, byte order and sign.
    115     *
    116     * @param tclass
    117     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    118     * @param tsize
    119     *            the size must be multiples H5T_STD_REF.
    120     * @param torder
    121     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
    122     *            ORDER_NONE and NATIVE.
    123     * @param tsign
    124     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
    125     *
    126     * @throws Exception
    127     *            if there is an error
    128     */
    129    public H5ReferenceType(int tclass, int tsize, int torder, int tsign) throws Exception {
    130        this(tclass, tsize, torder, tsign, null);
    131    }
    132
    133    /**
    134     * Constructs a H5ReferenceType with specified class, size, byte order and sign.
    135     *
    136     * @param tclass
    137     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    138     * @param tsize
    139     *            the size must be multiples H5T_STD_REF.
    140     * @param torder
    141     *            the byte order of the datatype. Valid values are ORDER_LE, ORDER_BE, ORDER_VAX,
    142     *            ORDER_NONE and NATIVE.
    143     * @param tsign
    144     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and NATIVE.
    145     * @param tbase
    146     *            the base datatype of the new datatype
    147     *
    148     * @throws Exception
    149     *            if there is an error
    150     */
    151    public H5ReferenceType(int tclass, int tsize, int torder, int tsign, Datatype tbase) throws Exception {
    152        this(tclass, tsize, torder, tsign, tbase, null);
    153    }
    154
    155    /**
    156     * Constructs a H5ReferenceType with specified class, size, byte order and sign.
    157     *
    158     * @param tclass
    159     *            the class of the datatype, e.g. CLASS_INTEGER, CLASS_FLOAT and etc.
    160     * @param tsize
    161     *            the size must be multiples H5T_STD_REF.
    162     * @param torder
    163     *            the byte order of the datatype. Valid values are ORDER_LE,
    164     *            ORDER_BE, ORDER_VAX, ORDER_NONE and NATIVE.
    165     * @param tsign
    166     *            the sign of the datatype. Valid values are SIGN_NONE, SIGN_2 and
    167     *            NATIVE.
    168     * @param tbase
    169     *            the base datatype of the new datatype
    170     * @param pbase
    171     *            the parent datatype of the new datatype
    172     *
    173     * @throws Exception
    174     *            if there is an error
    175     */
    176    public H5ReferenceType(int tclass, int tsize, int torder, int tsign, Datatype tbase, Datatype pbase) throws Exception {
    177        super(tclass, tsize, torder, tsign, tbase, pbase);
    178
    179        log.trace("constructor tsize {}", tsize);
    180        refdata = null;
    181    }
    182
    183    /**
    184     * Constructs a H5ReferenceType with a given native datatype identifier.
    185     *
    186     * @see #fromNative(long nativeID)
    187     *
    188     * @param theFile
    189     *            the file that contains the datatype.
    190     * @param theSize
    191     *            the size must be multiples H5T_STD_REF.
    192     * @param nativeID
    193     *            the native datatype identifier.
    194     *
    195     * @throws Exception
    196     *            if there is an error
    197     */
    198    public H5ReferenceType(FileFormat theFile, long theSize, long nativeID) throws Exception {
    199        this(theFile, theSize, nativeID, null);
    200    }
    201
    202    /**
    203     * Constructs a H5ReferenceType with a given native datatype identifier.
    204     *
    205     * @see #fromNative(long nativeID)
    206     *
    207     * @param theFile
    208     *            the file that contains the datatype.
    209     * @param theSize
    210     *            the size is the number of H5ReferenceData data structs.
    211     * @param nativeID
    212     *            the native datatype identifier.
    213     * @param pbase
    214     *            the parent datatype of the new datatype
    215     *
    216     * @throws Exception
    217     *            if there is an error
    218     */
    219    public H5ReferenceType(FileFormat theFile, long theSize, long nativeID, Datatype pbase) throws Exception {
    220        super(theFile, nativeID, pbase);
    221
    222        log.trace("constructor theSize {}", theSize);
    223        refsize = theSize;
    224        refdata = new ArrayList<>((int)theSize);
    225    }
    226
    227    /**
    228     * Clears memory held by the reference, such as the data buffer.
    229     */
    230    @SuppressWarnings("rawtypes")
    231    public void clear() {
    232        if (refdata != null) {
    233            if (refdata instanceof List)
    234                ((List) refdata).clear();
    235            originalRefBuf = null;
    236        }
    237        isDataLoaded = false;
    238    }
    239
    240    /**
    241     * Writes the memory buffer of this reference to file.
    242     *
    243     * @throws Exception if buffer can not be written
    244     */
    245    public final void write() throws Exception {
    246        log.trace("H5ReferenceType: write enter");
    247        if (refdata != null) {
    248            log.trace("H5ReferenceType: write data");
    249            //write(refdata);
    250        }
    251    }
    252
    253    /**
    254     * The status of initialization for this object
    255     *
    256     * @return true if the data has been initialized
    257     */
    258    public final boolean isInited() {
    259        return inited;
    260    }
    261
    262    /**
    263     * setData() loads the reference raw data into the buffer. This
    264     * buffer will be accessed to get the reference strings and data.
    265     * Once the references are destroyed, the refdata can only be used
    266     * to retrieve existing data.
    267     *
    268     * @param theData
    269     *            the data to write.
    270     */
    271    public void setData(List theData) {
    272        log.trace("setData(List): refsize={} theData={}", refsize, theData);
    273        for (int i = 0; i < (int)refsize; i++) {
    274            H5ReferenceData rf = (H5ReferenceData)theData.get(i);
    275            refdata.add(rf);
    276        }
    277        isDataLoaded = true;
    278        init();
    279    }
    280
    281    /**
    282     * setData() loads the reference raw data into the buffer. This
    283     * buffer will be accessed to get the reference strings and data.
    284     * Once the references are destroyed, the refdata can only be used
    285     * to retrieve existing data.
    286     *
    287     * @param theData
    288     *            the data to write.
    289     */
    290    public void setData(Object theData) {
    291        log.trace("setData(): refsize={} theData={}", refsize, theData);
    292        originalRefBuf = theData;
    293        for (int i = 0; i < (int)refsize; i++) {
    294            byte[] refarr = new byte[(int) datatypeSize];
    295            byte[] rElements = null;
    296            if (theData instanceof ArrayList) {
    297                rElements = (byte[]) ((ArrayList) theData).get(i);
    298                System.arraycopy(rElements, 0, refarr, 0, (int)datatypeSize);
    299            }
    300            else {
    301                rElements = (byte[]) theData;
    302                int refIndex = (int)datatypeSize * i;
    303                System.arraycopy(rElements, refIndex, refarr, 0, (int)datatypeSize);
    304            }
    305            log.trace("setData(): refarr={}", refarr);
    306            H5ReferenceData rf = new H5ReferenceData(refarr, datatypeSize);
    307            refdata.add(rf);
    308        }
    309        isDataLoaded = true;
    310        init();
    311    }
    312
    313    /**
    314     * Returns the data buffer of the reference in memory.
    315     *
    316     * If data is already loaded into memory, returns the data; otherwise, calls
    317     * read() to read data from file into a memory buffer and returns the memory
    318     * buffer.
    319     *
    320     * By default, the whole reference is read into memory.
    321     *
    322     * @return the memory buffer of the reference.
    323     *
    324     * @throws Exception if object can not be read
    325     * @throws OutOfMemoryError if memory is exhausted
    326     */
    327    public Object getData() throws Exception, OutOfMemoryError {
    328        log.trace("getData(): isDataLoaded={}", isDataLoaded);
    329        if (!isDataLoaded) {
    330            //refdata = read(); // load the data
    331            log.trace("getData(): size={} refdata={}", refdata.size(), refdata);
    332            if (refdata != null) {
    333                refsize = refdata.size();
    334                originalRefBuf = refdata;
    335                isDataLoaded = true;
    336            }
    337        }
    338
    339        return refdata;
    340    }
    341
    342    /**
    343     * Clears the current data buffer in memory and forces the next read() to load
    344     * the data from file.
    345     *
    346     * The function read() loads data from file into memory only if the data is
    347     * not read. If data is already in memory, read() just returns the memory
    348     * buffer. Sometimes we want to force read() to re-read data from file. For
    349     * example, when the selection is changed, we need to re-read the data.
    350     *
    351     * @see #getData()
    352     */
    353    public void clearData() {
    354        isDataLoaded = false;
    355    }
    356
    357    /**
    358     * Returns the array size of the reference.
    359     *
    360     * @return the array size of the reference.
    361     */
    362    public final long getRefSize() {
    363        if (!inited)
    364            init();
    365
    366        return refsize;
    367    }
    368
    369    /**
    370     * Sets the array size of the reference.
    371     *
    372     * @param current_size
    373     *        the array size of the current reference.
    374     */
    375    public final void setRefSize(long current_size) {
    376        refsize = current_size;
    377    }
    378//    public byte[] getOriginalrData() {
    379//        if (isDataLoaded)
    380//            return originalRefBuf;
    381//    }
    382
    383    /**
    384     * Retrieves reference information from file into memory.
    385     */
    386    public void init() {
    387        if (inited) {
    388            log.trace("init(): H5ReferenceType already inited");
    389            return;
    390        }
    391
    392        log.trace("init(): refsize={}", refsize);
    393        for (int i = 0; i < (int)refsize; i++) {
    394            H5ReferenceData rf = refdata.get(i);
    395            log.trace("init(): rf.ref_array={}", rf.ref_array);
    396            byte[] refarr = new byte[(int) datatypeSize];
    397            System.arraycopy(rf.ref_array, 0, refarr, 0, (int)datatypeSize);
    398
    399            if (zeroArrayCheck(refarr)) {
    400                log.trace("init(): refarr is zero");
    401                rf.file_fullpath = "NULL";
    402                rf.file_name = "NULL";
    403                rf.obj_name = "NULL";
    404                rf.attr_name = "NULL";
    405                rf.region_type = "NULL";
    406                rf.region_desc = "NULL";
    407            }
    408            else {
    409                log.trace("init(): refarr={}", refarr);
    410                try {
    411                    rf.file_fullpath = "NULL";
    412                    rf.file_name = "NULL";
    413                    rf.obj_name = "NULL";
    414                    rf.attr_name = "NULL";
    415                    if (isStdRef()) {
    416                        try {
    417                            rf.file_fullpath = H5.H5Rget_file_name(refarr);
    418                            log.trace("Reference Full File Path {}", rf.file_fullpath);
    419                            String[] split = rf.file_fullpath.split( Pattern.quote("/") );
    420                            rf.file_name = split[split.length-1];
    421                            log.trace("Reference File Name {}", rf.file_name);
    422                            rf.obj_name = H5.H5Rget_obj_name(refarr, HDF5Constants.H5P_DEFAULT);
    423                            log.trace("Reference Object Name {}", rf.obj_name);
    424
    425                            if (H5.H5Rget_type(refarr) == HDF5Constants.H5R_ATTR)
    426                                rf.attr_name = H5.H5Rget_attr_name(refarr);
    427                            else
    428                                rf.attr_name = "NULL";
    429                            log.trace("Reference Attribute Name {}", rf.attr_name);
    430                        }
    431                        catch (Exception ex) {
    432                            log.debug("Reference H5Rget_*_name", ex);
    433                        }
    434                    }
    435                    else if (isRegRef()) {
    436                        try {
    437                            rf.obj_name = H5.H5Rget_name_string(getFID(), HDF5Constants.H5R_DATASET_REGION, refarr);
    438                        }
    439                        catch (Exception ex) {
    440                            log.debug("Reference H5Rget_*_name", ex);
    441                        }
    442                    }
    443                    else {
    444                        try {
    445                            rf.obj_name = H5.H5Rget_name_string(getFID(), HDF5Constants.H5R_OBJECT, refarr);
    446                        }
    447                        catch (Exception ex) {
    448                            log.debug("Reference H5Rget_*_name", ex);
    449                        }
    450                    }
    451                    initReferenceRegion(i, refarr, false);
    452                }
    453                catch (Exception ex) {
    454                    log.debug("Reference Init", ex);
    455                }
    456            }
    457        }
    458        if (isStdRef()) {
    459            for (int i = 0; i < (int)refsize; i++) {
    460                H5ReferenceData rf = refdata.get(i);
    461                log.trace("init(): H5Rdestroy {}", rf.ref_array);
    462                byte[] refarr = new byte[(int) datatypeSize];
    463                System.arraycopy(rf.ref_array, 0, refarr, 0, (int)datatypeSize);
    464                H5.H5Rdestroy(refarr);
    465            }
    466        }
    467        log.trace("init(): finished");
    468        inited = true;
    469    }
    470
    471    private void initReferenceRegion(int refndx, byte[] refarr, boolean showData) {
    472        H5ReferenceData rf = refdata.get(refndx);
    473        rf.ref_type = HDF5Constants.H5R_BADTYPE;
    474        rf.obj_type = HDF5Constants.H5O_TYPE_UNKNOWN;
    475        rf.region_type = "NULL";
    476        rf.region_desc = "NULL";
    477        log.trace("initReferenceRegion start not null");
    478        if (isStdRef()) {
    479            try {
    480                rf.ref_type = (int)H5.H5Rget_type(refarr);
    481                log.debug("initReferenceRegion ref_type={}", rf.ref_type);
    482                try {
    483                    rf.obj_type = H5.H5Rget_obj_type3(refarr, HDF5Constants.H5P_DEFAULT);
    484                    log.debug("initReferenceRegion obj_type={}", rf.obj_type);
    485                }
    486                catch (Exception ex2) {
    487                    log.debug("initReferenceRegion H5Rget_obj_type3", ex2);
    488                }
    489            }
    490            catch (Exception ex1) {
    491                log.debug("initReferenceRegion H5Rget_type", ex1);
    492            }
    493
    494            if (rf.ref_type > HDF5Constants.H5R_BADTYPE) {
    495                if (rf.ref_type == HDF5Constants.H5R_OBJECT1) {
    496                    log.trace("initReferenceRegion H5R_OBJECT1");
    497                    if (rf.obj_type == HDF5Constants.H5O_TYPE_DATASET) {
    498                        initRegionDataset(refndx, refarr);
    499                    } //obj_type == HDF5Constants.H5O_TYPE_DATASET
    500                    else {
    501                        /* Object references -- show the type and OID of the referenced object. */
    502                        rf.region_type = "H5O_TYPE_OBJ_REF";
    503                        H5O_info_t objInfo;
    504                        long new_obj_id = HDF5Constants.H5I_INVALID_HID;
    505                        try {
    506                            new_obj_id = H5.H5Rdereference(getFID(), HDF5Constants.H5P_DEFAULT,
    507                                                           HDF5Constants.H5R_OBJECT, refarr);
    508                            objInfo = H5.H5Oget_info(new_obj_id);
    509                            if (objInfo.type == HDF5Constants.H5O_TYPE_GROUP)
    510                                rf.region_desc = "GROUP";
    511                            else if (objInfo.type == HDF5Constants.H5O_TYPE_DATASET)
    512                                rf.region_desc = "DATASET";
    513                            else if (objInfo.type == HDF5Constants.H5O_TYPE_NAMED_DATATYPE)
    514                                rf.region_desc = "DATATYPE";
    515                            else
    516                                rf.region_desc = "UNKNOWN " + objInfo.type;
    517                        }
    518                        catch (Exception ex2) {
    519                            log.debug("typeObjectRef ", ex2);
    520                        }
    521                        finally {
    522                            H5.H5Dclose(new_obj_id);
    523                        }
    524                    }
    525                }
    526                else if (rf.ref_type == HDF5Constants.H5R_DATASET_REGION1) {
    527                    log.trace("initReferenceRegion H5R_DATASET_REGION1");
    528                    initRegionDataset(refndx, refarr);
    529                }
    530                else if (rf.ref_type == HDF5Constants.H5R_OBJECT2) {
    531                    log.trace("initReferenceRegion H5R_OBJECT2");
    532                    rf.region_type = "H5O_TYPE_OBJ_REF";
    533                }
    534                else if (rf.ref_type == HDF5Constants.H5R_DATASET_REGION2) {
    535                    log.trace("initReferenceRegion H5R_DATASET_REGION2");
    536                    initRegionDataset(refndx, refarr);
    537                }
    538                else if (rf.ref_type == HDF5Constants.H5R_ATTR) {
    539                    log.trace("initReferenceRegion H5R_ATTR");
    540                    rf.region_type = "H5R_ATTR";
    541                    initRegionAttribute(refndx, refarr);
    542                }
    543                else {
    544                    log.trace("initReferenceRegion OTHER");
    545                    rf.region_type = "UNKNOWN";
    546                }
    547            }
    548        }
    549        else {
    550            if (isRegRef()) {
    551                rf.ref_type = HDF5Constants.H5R_DATASET_REGION1;
    552                rf.obj_type = HDF5Constants.H5O_TYPE_DATASET;
    553                int region_type = typeObjectRef(getFID(), HDF5Constants.H5R_DATASET_REGION, refarr);
    554                if (HDF5Constants.H5S_SEL_POINTS == region_type)
    555                    rf.region_type = "REGION_TYPE POINT";
    556                else if (HDF5Constants.H5S_SEL_HYPERSLABS == region_type)
    557                    rf.region_type = "REGION_TYPE BLOCK";
    558                else
    559                    rf.region_type = "REGION_TYPE UNKNOWN";
    560                rf.region_desc = descRegionDataset(getFID(), refarr);
    561            }
    562            else {
    563                rf.ref_type = HDF5Constants.H5R_OBJECT1;
    564                rf.obj_type = typeObjectRef(getFID(), HDF5Constants.H5R_OBJECT, refarr);
    565                rf.region_type = "H5O_TYPE_OBJ_REF";
    566            }
    567        }
    568        log.trace("initReferenceRegion finish");
    569    }
    570
    571    private void initRegionAttribute(int refndx, byte[] refarr) {
    572        H5ReferenceData rf = refdata.get(refndx);
    573        long new_obj_id = HDF5Constants.H5I_INVALID_HID;
    574        try {
    575            log.trace("initRegionAttribute refarr2={}:", refarr);
    576            new_obj_id = H5.H5Ropen_attr(refarr, HDF5Constants.H5P_DEFAULT, HDF5Constants.H5P_DEFAULT);
    577            long new_obj_sid = HDF5Constants.H5I_INVALID_HID;
    578            try {
    579                new_obj_sid = H5.H5Aget_space(new_obj_id);
    580                long reg_ndims = H5.H5Sget_simple_extent_ndims(new_obj_sid);
    581                //rf.region_desc = dump_region_attrs(regStr, new_obj_id);
    582            }
    583            catch (Exception ex3) {
    584                log.debug("initRegionAttribute Space Open", ex3);
    585            }
    586            finally {
    587                H5.H5Sclose(new_obj_sid);
    588            }
    589            log.trace("initRegionAttribute finish");
    590        }
    591        catch (Exception ex2) {
    592            log.debug("initRegionAttribute ", ex2);
    593        }
    594        finally {
    595            H5.H5Aclose(new_obj_id);
    596        }
    597    }
    598
    599    private void initRegionDataset(int refndx, byte[] refarr) {
    600        H5ReferenceData rf = refdata.get(refndx);
    601        long new_obj_id = HDF5Constants.H5I_INVALID_HID;
    602        try {
    603            log.trace("initRegionDataset refarr2={}:", refarr);
    604            new_obj_id = H5.H5Ropen_object(refarr, HDF5Constants.H5P_DEFAULT, HDF5Constants.H5P_DEFAULT);
    605            long new_obj_sid = HDF5Constants.H5I_INVALID_HID;
    606            try {
    607                log.trace("initRegionDataset refarr3={}:", refarr);
    608                new_obj_sid = H5.H5Ropen_region(refarr, HDF5Constants.H5P_DEFAULT, HDF5Constants.H5P_DEFAULT);
    609                try {
    610                    int region_type = H5.H5Sget_select_type(new_obj_sid);
    611                    log.debug("Reference Region Type {}", region_type);
    612                    long reg_ndims = H5.H5Sget_simple_extent_ndims(new_obj_sid);
    613                    StringBuilder sb = new StringBuilder();
    614                    if (HDF5Constants.H5S_SEL_POINTS == region_type) {
    615                        rf.region_type = "REGION_TYPE POINT";
    616                        long reg_npoints = H5.H5Sget_select_elem_npoints(new_obj_sid);
    617                        long getcoord[] = new long[(int)(reg_ndims * reg_npoints)];
    618                        try {
    619                            H5.H5Sget_select_elem_pointlist(new_obj_sid, 0, reg_npoints, getcoord);
    620                        }
    621                        catch (Exception ex5) {
    622                            log.debug("initRegionDataset H5.H5Sget_select_elem_pointlist: ", ex5);
    623                        }
    624                        sb.append("{ ");
    625                        for (int i = 0; i < (int)reg_npoints; i++) {
    626                            if (i > 0)
    627                                sb.append(" ");
    628                            sb.append("(");
    629                            for (int j = 0; j < (int)reg_ndims; j++) {
    630                                if (j > 0)
    631                                    sb.append(",");
    632                                sb.append(getcoord[i * (int)reg_ndims + j]);
    633                            }
    634                            sb.append(")");
    635                        }
    636                        sb.append(" }");
    637                        rf.region_desc = sb.toString();
    638                    }
    639                    else if (HDF5Constants.H5S_SEL_HYPERSLABS == region_type) {
    640                        rf.region_type = "REGION_TYPE BLOCK";
    641                        long reg_nblocks = H5.H5Sget_select_hyper_nblocks(new_obj_sid);
    642                        long getblocks[] = new long[(int)(reg_ndims * reg_nblocks) * 2];
    643                        try {
    644                            H5.H5Sget_select_hyper_blocklist(new_obj_sid, 0, reg_nblocks, getblocks);
    645                        }
    646                        catch (Exception ex5) {
    647                            log.debug("initRegionDataset H5.H5Sget_select_hyper_blocklist: ", ex5);
    648                        }
    649                        sb.append("{ ");
    650                        for (int i = 0; i < (int)reg_nblocks; i++) {
    651                            if (i > 0)
    652                                sb.append(" ");
    653                            sb.append("(");
    654                            for (int j = 0; j < (int)reg_ndims; j++) {
    655                                if (j > 0)
    656                                    sb.append(",");
    657                                sb.append(getblocks[i * 2 * (int)reg_ndims + j]);
    658                            }
    659                            sb.append(")-(");
    660                            for (int j = 0; j < (int)reg_ndims; j++) {
    661                                if (j > 0)
    662                                    sb.append(",");
    663                                sb.append(getblocks[i * 2 * (int)reg_ndims + (int)reg_ndims + j]);
    664                            }
    665                            sb.append(")");
    666                        }
    667                        sb.append(" }");
    668                        rf.region_desc = sb.toString();
    669                    }
    670                    else
    671                        rf.region_type = "REGION_TYPE UNKNOWN";
    672                }
    673                catch (Exception ex4) {
    674                    log.debug("initRegionDataset Region Type", ex4);
    675                }
    676            }
    677            catch (Exception ex3) {
    678                log.debug("initRegionDataset Space Open", ex3);
    679            }
    680            finally {
    681                H5.H5Sclose(new_obj_sid);
    682            }
    683            log.trace("initRegionDataset finish");
    684        }
    685        catch (Exception ex2) {
    686            log.debug("initRegionDataset ", ex2);
    687        }
    688        finally {
    689            H5.H5Dclose(new_obj_id);
    690        }
    691    }
    692
    693    /**
    694     * Checks if a reference datatype is all zero.
    695     *
    696     * @param refarr
    697     *            the reference datatype data to be checked.
    698     *
    699     * @return true is the reference datatype data is all zero; otherwise returns false.
    700     */
    701    public static final boolean zeroArrayCheck(final byte[] refarr) {
    702        for (byte b : refarr) {
    703            if (b != 0)
    704                return false;
    705        }
    706        return true;
    707    }
    708
    709    /**
    710     * Get the reference datatype reference name.
    711     *
    712     * @param refarr
    713     *            the reference datatype data to be queried.
    714     *
    715     * @return the reference datatype name string, null otherwise.
    716     */
    717    public final String getObjectReferenceName(byte[] refarr) {
    718        if (!inited)
    719            init();
    720
    721        // find the index that matches refarr and ref_array
    722        H5ReferenceData rf = null;
    723        for (int i = 0; i < (int)refsize; i++) {
    724            byte[] theref = refdata.get(i).ref_array;
    725            if (Arrays.equals(theref, refarr)) {
    726                rf = refdata.get(i);
    727                break;
    728            }
    729        }
    730        if (rf == null)
    731            return null;
    732
    733        StringBuilder sb = new StringBuilder();
    734        if (!rf.obj_name.equals("NULL")) {
    735            sb.append(rf.obj_name);
    736        }
    737        if (!rf.attr_name.equals("NULL")) {
    738            if (sb.length() > 0)
    739                sb.append("/");
    740            sb.append(rf.attr_name);
    741        }
    742        if (!rf.region_desc.equals("NULL")) {
    743            if (sb.length() > 0)
    744                sb.append(" ");
    745            sb.append(rf.region_desc);
    746        }
    747        log.debug("Reference Object Name {}", sb);
    748        return sb.toString();
    749    }
    750
    751    /**
    752     * Get the reference datatype reference name.
    753     *
    754     * @param refarr
    755     *            the reference datatype data to be queried.
    756     *
    757     * @return the reference datatype name string, null otherwise.
    758     */
    759    public final String getFullReferenceName(byte[] refarr) {
    760        if (!inited)
    761            init();
    762
    763        // find the index that matches refarr and ref_array
    764        H5ReferenceData rf = null;
    765        for (int i = 0; i < (int)refsize; i++) {
    766            byte[] theref = refdata.get(i).ref_array;
    767            if (Arrays.equals(theref, refarr)) {
    768                rf = refdata.get(i);
    769                break;
    770            }
    771        }
    772        if (rf == null)
    773            return null;
    774
    775        StringBuilder sb = new StringBuilder();
    776        if (!rf.file_name.equals("NULL"))
    777            sb.append(rf.file_name);
    778        if (!rf.obj_name.equals("NULL")) {
    779            if (sb.length() > 0)
    780                sb.append("/");
    781            sb.append(rf.obj_name);
    782        }
    783        if (!rf.attr_name.equals("NULL")) {
    784            if (sb.length() > 0)
    785                sb.append("/");
    786            sb.append(rf.attr_name);
    787        }
    788        if (!rf.region_desc.equals("NULL")) {
    789            if (sb.length() > 0)
    790                sb.append(" ");
    791            sb.append(rf.region_desc);
    792        }
    793        log.debug("Full Reference Name {}", sb);
    794        return sb.toString();
    795    }
    796
    797
    798    /**
    799     * Get the reference datatype dataset region reference as string.
    800     *
    801     * @param refarr
    802     *            the reference datatype data to be queried.
    803     *
    804     * @return the reference datatype name string, null otherwise.
    805     */
    806    public final String getRegionDataset(byte[] refarr) {
    807        if (!inited)
    808            init();
    809
    810        // find the index that matches refarr and ref_array
    811        H5ReferenceData rf = null;
    812        for (int i = 0; i < (int)refsize; i++) {
    813            byte[] theref = refdata.get(i).ref_array;
    814            if (Arrays.equals(theref, refarr)) {
    815                rf = refdata.get(i);
    816                break;
    817            }
    818        }
    819        if (rf == null)
    820            return null;
    821
    822        StringBuilder sb = new StringBuilder();
    823        sb.append(rf.region_type);
    824        if (!rf.region_desc.equals("NULL")) {
    825            if (sb.length() > 0)
    826                sb.append(" ");
    827            sb.append(rf.region_desc);
    828        }
    829        log.debug("getRegionDataset Value {}", sb);
    830        return sb.toString();
    831    }
    832
    833    /**
    834     * Get the reference datatype data.
    835     *
    836     * @param refarr
    837     *            the reference datatype data to be queried.
    838     *
    839     * @return the reference datatype data.
    840     */
    841    public final H5ReferenceData getReferenceData(byte[] refarr) {
    842        if (!inited)
    843            init();
    844
    845        // find the index that matches refarr and ref_array
    846        H5ReferenceData rf = null;
    847        for (int i = 0; i < (int)refsize; i++) {
    848            byte[] theref = refdata.get(i).ref_array;
    849            if (Arrays.equals(theref, refarr)) {
    850                rf = refdata.get(i);
    851                break;
    852            }
    853        }
    854        return rf;
    855    }
    856
    857    /**
    858     * Get the reference datatype region reference as string.
    859     *
    860     * @param refarr
    861     *            the reference datatype data to be queried.
    862     * @param showData
    863     *            show the reference region dims
    864     *
    865     * @return the reference datatype name string, null otherwise.
    866     */
    867    public final String getReferenceRegion(byte[] refarr, boolean showData) {
    868        if (!inited)
    869            init();
    870
    871        log.trace("getReferenceRegion refarr {}", refarr);
    872        // find the index that matches refarr and ref_array
    873        H5ReferenceData rf = null;
    874        for (int i = 0; i < (int)refsize; i++) {
    875            byte[] theref = refdata.get(i).ref_array;
    876            log.trace("getReferenceRegion theref {}", theref);
    877            if (Arrays.equals(theref, refarr)) {
    878                rf = refdata.get(i);
    879                log.trace("getReferenceRegion rf {}", rf);
    880                break;
    881            }
    882        }
    883        if (rf == null)
    884            return null;
    885
    886        StringBuilder objsb = new StringBuilder();
    887        if (!rf.file_name.equals("NULL"))
    888            objsb.append(rf.file_name);
    889        if (!rf.obj_name.equals("NULL")) {
    890            objsb.append(rf.obj_name);
    891        }
    892        if (!rf.attr_name.equals("NULL")) {
    893            if (objsb.length() > 0)
    894                objsb.append("/");
    895            objsb.append(rf.attr_name);
    896        }
    897        log.debug("getReferenceRegion Region Name {}", objsb);
    898
    899        StringBuilder regsb = new StringBuilder();
    900        if (!rf.region_type.equals("NULL"))
    901            regsb.append(rf.region_type);
    902        if (!rf.region_desc.equals("NULL")) {
    903            if (regsb.length() > 0)
    904                regsb.append(" ");
    905            regsb.append(rf.region_desc);
    906        }
    907        log.debug("getReferenceRegion Region Type {}", regsb);
    908        StringBuilder sb = new StringBuilder(objsb);
    909        if (regsb.length() > 0) {
    910            sb.append(" ");
    911            sb.append(regsb);
    912        }
    913        if (sb.length() > 0)
    914            return sb.toString();
    915        else
    916            return "NULL";
    917    }
    918
    919    /**
    920     * Returns a string representation of the data value. For
    921     * example, "0, 255".
    922     *
    923     * For a compound datatype, it will be a 1D array of strings with field
    924     * members separated by the delimiter. For example,
    925     * "{0, 10.5}, {255, 20.0}, {512, 30.0}" is a compound attribute of {int,
    926     * float} of three data points.
    927     *
    928     * @param delimiter
    929     *            The delimiter used to separate individual data points. It
    930     *            can be a comma, semicolon, tab or space. For example,
    931     *            toString(",") will separate data by commas.
    932     *
    933     * @return the string representation of the data values.
    934     */
    935    public String toString(String delimiter) {
    936        return toString(delimiter, -1);
    937    }
    938
    939    /**
    940     * Returns a string representation of the data value.
    941     *
    942     * @param delimiter
    943     *            The delimiter used to separate individual data points. It
    944     *            can be a comma, semicolon, tab or space. For example,
    945     *            toString(",") will separate data by commas.
    946     * @param maxItems
    947     *            The maximum number of Array values to return
    948     *
    949     * @return the string representation of the data values.
    950     */
    951    public String toString(String delimiter, int maxItems) {
    952        Object theData = originalRefBuf;
    953        if (theData == null) {
    954            log.debug("toString: value is null");
    955            return null;
    956        }
    957
    958        if (theData instanceof List<?>) {
    959            log.trace("toString: value is list");
    960            return null;
    961        }
    962
    963        Class<? extends Object> valClass = theData.getClass();
    964
    965        if (!valClass.isArray()) {
    966            log.trace("toString: finish - not array");
    967            String strValue = theData.toString();
    968            if (maxItems > 0 && strValue.length() > maxItems)
    969                // truncate the extra characters
    970                strValue = strValue.substring(0, maxItems);
    971            return strValue;
    972        }
    973
    974        // value is an array
    975        StringBuilder sb = new StringBuilder();
    976        log.trace("toString: refsize={} isStdRef={} Array.getLength={}", refsize, isStdRef(), Array.getLength(theData));
    977        if (isStdRef()) {
    978            String cname = valClass.getName();
    979            char dname = cname.charAt(cname.lastIndexOf('[') + 1);
    980            log.trace("toString: isStdRef with cname={} dname={}", cname, dname);
    981            for (int i = 0; i < (int)refsize; i++) {
    982                int refIndex = HDF5Constants.H5R_REF_BUF_SIZE * i;
    983                byte[] refarr = new byte[(int) HDF5Constants.H5R_REF_BUF_SIZE];
    984                System.arraycopy(theData, refIndex, refarr, 0, (int)HDF5Constants.H5R_REF_BUF_SIZE);
    985                log.trace("toString: refarr[{}]={}", i, refarr);
    986                String refarr_str = getReferenceRegion(refarr, false);
    987                StringBuilder ref_str = null;
    988                if (refarr_str != null) {
    989                    ref_str = new StringBuilder(refarr_str);
    990                    if ((maxItems > 0) && (ref_str.length() > maxItems)) {
    991                        ref_str.setLength(maxItems);
    992                    }
    993                    log.trace("toString: ref_str[{}]={}", i, ref_str);
    994                }
    995                else
    996                    ref_str = new StringBuilder("NULL");
    997                if (i > 0)
    998                    sb.append(", ");
    999                sb.append(ref_str);
    1000            }
    1001            return sb.toString();
    1002        }
    1003        return toString(delimiter, maxItems);
    1004    }
    1005
    1006    /**
    1007     * The individual reference data for a given object.
    1008     */
    1009    public static class H5ReferenceData
    1010    {
    1011        private static final Logger log = LoggerFactory.getLogger(H5ReferenceData.class);
    1012
    1013        /** The reference array raw data */
    1014        public byte[] ref_array = null;
    1015
    1016        /** The the full file path referenced */
    1017        public String file_fullpath;
    1018
    1019        /** The file name referenced */
    1020        public String file_name;
    1021
    1022        /** The object name referenced */
    1023        public String obj_name;
    1024
    1025        /** The attribute name referenced */
    1026        public String attr_name;
    1027
    1028        /** The type of region referenced */
    1029        public String region_type;
    1030
    1031        /** The point/block description of region referenced */
    1032        public String region_desc;
    1033
    1034        /** The default type of region referenced */
    1035        public int ref_type = HDF5Constants.H5R_BADTYPE;
    1036
    1037        /** The default type of object referenced */
    1038        public int obj_type = HDF5Constants.H5O_TYPE_UNKNOWN;
    1039
    1040        /** The type size of object referenced */
    1041        public long typeSize;
    1042
    1043        /**
    1044         *  Copy the individual reference array for further processing
    1045         *
    1046         * @param theArray
    1047         *            the reference datatype data to be copied.
    1048         */
    1049        H5ReferenceData(byte[] theArray, long theTypeSize)
    1050        {
    1051            typeSize = theTypeSize;
    1052            ref_array = new byte[(int)theTypeSize];
    1053            System.arraycopy(theArray, 0, ref_array, 0, (int)theTypeSize);
    1054        }
    1055    }
    1056}