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}