    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.h4;
    016
    017import java.util.List;
    018import java.util.Vector;
    019
    020import hdf.hdflib.HDFConstants;
    021import hdf.hdflib.HDFException;
    022import hdf.hdflib.HDFLibrary;
    023
    024import hdf.object.Attribute;
    025import hdf.object.CompoundDS;
    026import hdf.object.Dataset;
    027import hdf.object.Datatype;
    028import hdf.object.FileFormat;
    029import hdf.object.Group;
    030import hdf.object.MetaDataContainer;
    031
    032import hdf.object.h4.H4CompoundAttribute;
    033
    034/**
    035 * H4Vdata describes a multi-dimension array of HDF4 vdata, inheriting CompoundDS.
    036 *
    037 * A vdata is like a table that consists of a collection of records whose values
    038 * are stored in fixed-length fields. All records have the same structure and
    039 * all values in each field have the same data type. Vdatas are uniquely
    040 * identified by a name, a class, and a series of individual field names.
    041 *
    042 * <b>How to Select a Subset</b>
    043 *
    044 * Dataset defines APIs for reading, writing and subsetting a dataset. No function is
    045 * defined to select a subset of a data array. The selection is done in an implicit way.
    046 * Function calls to dimension information such as getSelectedDims() return an array
    047 * of dimension values, which is a reference to the array in the dataset object.
    048 * Changes of the array outside the dataset object directly change the values of
    049 * the array in the dataset object. It is like pointers in C.
    050 *
    051 * The following is an example of how to make a subset. In the example, the dataset
    052 * is a 4-dimension with size of [200][100][50][10], i.e.
    053 * dims[0]=200; dims[1]=100; dims[2]=50; dims[3]=10; <br>
    054 * We want to select every other data point in dims[1] and dims[2]
    055 * <pre>
    056     int rank = dataset.getRank();   // number of dimensions of the dataset
    057     long[] dims = dataset.getDims(); // the dimension sizes of the dataset
    058     long[] selected = dataset.getSelectedDims(); // the selected size of the dataet
    059     long[] start = dataset.getStartDims(); // the offset of the selection
    060     long[] stride = dataset.getStride(); // the stride of the dataset
    061     int[]  selectedIndex = dataset.getSelectedIndex(); // the selected dimensions for display
    062
    063     // select dim1 and dim2 as 2D data for display, and slice through dim0
    064     selectedIndex[0] = 1;
    065     selectedIndex[1] = 2;
    066     selectedIndex[1] = 0;
    067
    068     // reset the selection arrays
    069     for (int i=0; i&lt;rank; i++) {
    070         start[i] = 0;
    071         selected[i] = 1;
    072         stride[i] = 1;
    073    }
    074
    075    // set stride to 2 on dim1 and dim2 so that every other data point is selected.
    076    stride[1] = 2;
    077    stride[2] = 2;
    078
    079    // set the selection size of dim1 and dim2
    080    selected[1] = dims[1]/stride[1];
    081    selected[2] = dims[1]/stride[2];
    082
    083    // when dataset.read() is called, the selection above will be used since
    084    // the dimension arrays is passed by reference. Changes of these arrays
    085    // outside the dataset object directly change the values of these array
    086    // in the dataset object.
    087
    088 * </pre>
    089 *
    090 * @version 1.1 9/4/2007
    091 * @author Peter X. Cao
    092 */
    093public class H4Vdata extends CompoundDS implements MetaDataContainer
    094{
    095    private static final long serialVersionUID = -5978700886955419959L;
    096
    097    private static final org.slf4j.Logger       log = org.slf4j.LoggerFactory.getLogger(H4Vdata.class);
    098
    099    /**
    100     * The list of attributes of this data object. Members of the list are
    101     * instance of H4CompoundAttribute.
    102     */
    103    @SuppressWarnings("rawtypes")
    104    private List                                attributeList;
    105
    106    /**
    107     * Number of records of this Vdata table.
    108     */
    109    private int                                 numberOfRecords;
    110
    111    /**
    112     * The data types of the members of the compound dataset.
    113     */
    114    private long[]                              memberTIDs;
    115
    116    /** the number of attributes */
    117    private int                                 nAttributes = -1;
    118
    119
    120    /**
    121     * Creates an H4Vdata object with specific name and path.
    122     *
    123     * @param theFile the HDF file.
    124     * @param name the name of this H4Vdata.
    125     * @param path the full path of this H4Vdata.
    126     */
    127    public H4Vdata(FileFormat theFile, String name, String path) {
    128        this(theFile, name, path, null);
    129    }
    130
    131    /**
    132     * Creates an H4Vdata object with specific name, path and oid.
    133     *
    134     * @param theFile the HDF file.
    135     * @param name the name of this H4Vdata.
    136     * @param path the full path of this H4Vdata.
    137     * @param oid the unique identifier of this data object.
    138     */
    139    @SuppressWarnings("deprecation")
    140    public H4Vdata(FileFormat theFile, String name, String path, long[] oid) {
    141        super (theFile, name, path, oid);
    142        numberOfRecords = 0;
    143        numberOfMembers = 0;
    144        memberOrders = null;
    145    }
    146
    147    /*
    148     * (non-Javadoc)
    149     * @see hdf.object.DataFormat#hasAttribute()
    150     */
    151    @Override
    152    public boolean hasAttribute() {
    153        if (nAttributes < 0) {
    154            long id = open();
    155
    156            if (id >= 0) {
    157                try {
    158                    nAttributes = HDFLibrary.VSnattrs(id);
    159                }
    160                catch (Exception ex) {
    161                    log.debug("hasAttribute() failure: ", ex);
    162                    nAttributes = 0;
    163                }
    164
    165                log.trace("hasAttribute(): nAttributes={}", nAttributes);
    166
    167                close(id);
    168            }
    169        }
    170
    171        return (nAttributes > 0);
    172    }
    173
    174    // implementing Dataset
    175    /**
    176     * Returns the datatype of the data object.
    177     *
    178     * @return the datatype of the data object.
    179     */
    180    @Override
    181    public Datatype getDatatype() {
    182        if (!inited)
    183            init();
    184
    185        if (datatype == null) {
    186            try {
    187                datatype = new H4Datatype(-1);
    188            }
    189            catch (Exception ex) {
    190                log.debug("getDatatype(): failed to create datatype: ", ex);
    191                datatype = null;
    192            }
    193        }
    194
    195        return datatype;
    196    }
    197
    198    /**
    199     * Returns the fill values for the data object.
    200     *
    201     * @return the fill values for the data object.
    202     */
    203    @Override
    204    public Object getFillValue() {
    205        return null;
    206    }
    207
    208    // Implementing Dataset
    209    @Override
    210    public byte[] readBytes() throws HDFException {
    211        byte[] theData = null;
    212
    213        if (!isInited())
    214            init();
    215
    216        if (numberOfMembers <= 0) {
    217            log.debug("readBytes(): VData contains no members");
    218            return null; // this Vdata does not have any filed
    219        }
    220
    221        long id = open();
    222        if (id < 0) {
    223            log.debug("readBytes(): Invalid VData ID");
    224            return null;
    225        }
    226
    227        String allNames = memberNames[0];
    228        for (int i=0; i<numberOfMembers; i++)
    229            allNames += ","+memberNames[i];
    230
    231        try {
    232            // moves the access pointer to the start position
    233            HDFLibrary.VSseek(id, (int)startDims[0]);
    234            // Specify the fields to be accessed
    235            HDFLibrary.VSsetfields(id, allNames);
    236            int[] recordSize = {0};
    237            HDFLibrary.VSQueryvsize(id, recordSize);
    238            int size =recordSize[0] * (int)selectedDims[0];
    239            theData = new byte[size];
    240            HDFLibrary.VSread(id, theData, (int)selectedDims[0], HDFConstants.FULL_INTERLACE);
    241        }
    242        catch (Exception ex) {
    243            log.debug("readBytes(): failure: ", ex);
    244        }
    245        finally {
    246            close(id);
    247        }
    248
    249        return theData;
    250    }
    251
    252    // Implementing DataFormat
    253    /**
    254     * Reads the data from file.
    255     *
    256     * read() reads the data from file to a memory buffer and returns the memory
    257     * buffer. The dataset object does not hold the memory buffer. To store the
    258     * memory buffer in the dataset object, one must call getData().
    259     *
    260     * By default, the whole dataset is read into memory. Users can also select
    261     * a subset to read. Subsetting is done in an implicit way.
    262     *
    263     * @return the data read from file.
    264     *
    265     * @see #getData()
    266     *
    267     * @throws HDFException
    268     *             if object can not be read
    269     * @throws OutOfMemoryError
    270     *             if memory is exhausted
    271     */
    272    @SuppressWarnings({ "rawtypes", "unchecked", "deprecation" })
    273    @Override
    274    public Object read() throws HDFException {
    275        List list = null;
    276
    277        if (!isInited())
    278            init();
    279
    280        if (numberOfMembers <= 0) {
    281            log.debug("read(): VData contains no members");
    282            return null; // this Vdata does not have any filed
    283        }
    284
    285        long id = open();
    286        if (id < 0) {
    287            log.debug("read(): Invalid VData ID");
    288            return null;
    289        }
    290
    291        list = new Vector();
    292
    293        // assume external data files are located in the same directory as the main file.
    294        HDFLibrary.HXsetdir(getFileFormat().getParent());
    295
    296        Object member_data = null;
    297        for (int i=0; i<numberOfMembers; i++) {
    298            if (!isMemberSelected[i])
    299                continue;
    300
    301            try {
    302                // moves the access pointer to the start position
    303                HDFLibrary.VSseek(id, (int)startDims[0]);
    304                // Specify the fields to be accessed
    305                HDFLibrary.VSsetfields(id, memberNames[i]);
    306            }
    307            catch (HDFException ex) {
    308                log.debug("read(): failure: ", ex);
    309                isMemberSelected[i] = false;
    310                continue;
    311            }
    312
    313            int n = memberOrders[i]*(int)selectedDims[0];
    314
    315            member_data = H4Datatype.allocateArray(memberTIDs[i], n);
    316
    317            log.trace("read(): index={} isMemberSelected[i]={} memberOrders[i]={} array size={}", i, isMemberSelected[i], memberOrders[i], n);
    318            if (member_data == null) {
    319                String[] nullValues = new String[n];
    320                for (int j=0; j<n; j++)
    321                    nullValues[j] = "*ERROR*";
    322                list.add(nullValues);
    323                continue;
    324            }
    325
    326            try {
    327                HDFLibrary.VSread(id, member_data, (int)selectedDims[0], HDFConstants.FULL_INTERLACE);
    328                if ((memberTIDs[i] == HDFConstants.DFNT_CHAR) ||
    329                        (memberTIDs[i] ==  HDFConstants.DFNT_UCHAR8)) {
    330                    // convert characters to string
    331                    log.trace("read(): convert characters to string");
    332                    member_data = Dataset.byteToString((byte[])member_data, memberOrders[i]);
    333                    try {
    334                        memberTypes[i] = new H4Datatype(Datatype.CLASS_STRING, memberOrders[i], Datatype.NATIVE, Datatype.NATIVE);
    335                    }
    336                    catch (Exception ex) {
    337                        log.debug("read(): failed to create datatype for member[{}]: ", i, ex);
    338                        memberTypes[i] = null;
    339                    }
    340                    memberOrders[i] = 1; //one String
    341                }
    342                else if (H4Datatype.isUnsigned(memberTIDs[i])) {
    343                    // convert unsigned integer to appropriate Java integer
    344                    log.trace("read(): convert unsigned integer to appropriate Java integer");
    345                    member_data = Dataset.convertFromUnsignedC(member_data);
    346                }
    347            }
    348            catch (HDFException ex) {
    349                String[] nullValues = new String[n];
    350                for (int j=0; j<n; j++)
    351                    nullValues[j] = "*ERROR*";
    352                list.add(nullValues);
    353                continue;
    354            }
    355
    356            list.add(member_data);
    357        } //  (int i=0; i<numberOfMembers; i++)
    358
    359        close(id);
    360
    361        return list;
    362    }
    363
    364    // Implementing DataFormat
    365    /**
    366     * Writes a memory buffer to the object in the file.
    367     *
    368     * @param buf
    369     *            the data to write
    370     *
    371     * @throws HDFException
    372     *             if data can not be written
    373     */
    374    @Override
    375    public void write(Object buf) throws HDFException {
    376        //For writing to a vdata, VSsetfields can only be called once, to set
    377        //up the fields in a vdata. Once the vdata fields are set, they may
    378        //not be changed. Thus, to update some fields of a record after the
    379        //first write, the user must read all the fields to a buffer, update
    380        //the buffer, then write the entire record back to the vdata.
    381        log.trace("write(): disabled");
    382        /*
    383        if (buf == null || numberOfMembers <= 0 || !(buf instanceof List))
    384            return; // no data to write
    385
    386        List list = (List)buf;
    387        Object member_data = null;
    388        String member_name = null;
    389
    390        int vid = open();
    391        if (vid < 0) return;
    392
    393        int idx = 0;
    394        for (int i=0; i<numberOfMembers; i++) {
    395            if (!isMemberSelected[i])
    396                continue;
    397
    398            HDFLibrary.VSsetfields(vid, memberNames[i]);
    399
    400            try {
    401                // Specify the fields to be accessed
    402
    403                // moves the access pointer to the start position
    404                HDFLibrary.VSseek(vid, (int)startDims[0]);
    405            }
    406            catch (HDFException ex) {
    407                continue;
    408            }
    409
    410            member_data = list.get(idx++);
    411            if (member_data == null)
    412                continue;
    413
    414            if (memberTIDs[i] == HDFConstants.DFNT_CHAR ||
    415                memberTIDs[i] ==  HDFConstants.DFNT_UCHAR8) {
    416                member_data = Dataset.stringToByte((String[])member_data, memberOrders[i]);
    417            }
    418            else if (H4Datatype.isUnsigned(memberTIDs[i])) {
    419                // convert unsigned integer to appropriate Java integer
    420                member_data = Dataset.convertToUnsignedC(member_data);
    421            }
    422
    423
    424            int interlace = HDFConstants.NO_INTERLACE;
    425            try {
    426                int write_num = HDFLibrary.VSwrite(
    427                    vid, member_data, (int)selectedDims[0], interlace);
    428            }
    429            catch (HDFException ex) {
    430                log.debug("write():", ex);
    431            }
    432        } //  (int i=0; i<numberOfMembers; i++)
    433
    434        close(vid);
    435         */
    436    }
    437
    438    /**
    439     * Converts the data values of this data object to appropriate Java integers if
    440     * they are unsigned integers.
    441     *
    442     * @see hdf.object.Dataset#convertToUnsignedC(Object)
    443     * @see hdf.object.Dataset#convertFromUnsignedC(Object, Object)
    444     *
    445     * @return the converted data buffer.
    446     */
    447    @Override
    448    public Object convertFromUnsignedC() {
    449        throw new UnsupportedOperationException("H4Vdata:convertFromUnsignedC Unsupported operation.");
    450    }
    451
    452    /**
    453     * Converts Java integer data values of this data object back to unsigned C-type
    454     * integer data if they are unsigned integers.
    455     *
    456     * @see hdf.object.Dataset#convertToUnsignedC(Object)
    457     * @see hdf.object.Dataset#convertToUnsignedC(Object, Object)
    458     *
    459     * @return the converted data buffer.
    460     */
    461    @Override
    462    public Object convertToUnsignedC() {
    463        throw new UnsupportedOperationException("H4Vdata:convertToUnsignedC Unsupported operation.");
    464    }
    465
    466    // Implementing DataFormat
    467    /**
    468     * Retrieves the object's metadata, such as attributes, from the file.
    469     *
    470     * Metadata, such as attributes, is stored in a List.
    471     *
    472     * @return the list of metadata objects.
    473     *
    474     * @throws HDFException
    475     *             if the metadata can not be retrieved
    476     */
    477    @Override
    478    @SuppressWarnings({"rawtypes", "unchecked"})
    479    public List getMetadata() throws HDFException {
    480        if (attributeList != null) {
    481            log.trace("getMetdata(): attributeList != null");
    482            return attributeList;
    483        }
    484
    485        long id = open();
    486
    487        if (id < 0) {
    488            log.debug("getMetadata(): Invalid VData ID");
    489            return attributeList;
    490        }
    491
    492        int n = 0;
    493        try {
    494            n = HDFLibrary.VSnattrs(id);
    495
    496            if (n <= 0) {
    497                log.debug("getMetadata(): VData number of attributes <= 0");
    498                return attributeList;
    499            }
    500
    501            attributeList = new Vector(n, 5);
    502            boolean b = false;
    503            String[] attrName = new String[1];
    504            int[] attrInfo = new int[5];
    505
    506            // _HDF_VDATA (or -1) to specify the vdata attribute
    507            int nleft = n;
    508            for (int j = -1; j < numberOfMembers; j++) {
    509                for (int i = 0; i < nleft; i++) {
    510                    attrName[0] = "";
    511
    512                    try {
    513                        b = HDFLibrary.VSattrinfo(id, j, i, attrName, attrInfo);
    514                        // mask off the litend bit
    515                        attrInfo[0] = attrInfo[0] & (~HDFConstants.DFNT_LITEND);
    516                    }
    517                    catch (HDFException ex) {
    518                        log.debug("getMetadata(): attribute[{}] VSattrinfo failure: ", i, ex);
    519                        b = false;
    520                        ex.printStackTrace();
    521                    }
    522
    523                    if (!b || attrName[0].length() <= 0)
    524                        continue;
    525
    526                    long[] attrDims = {attrInfo[1]};
    527                    H4CompoundAttribute attr = new H4CompoundAttribute(this, attrName[0], new H4Datatype(attrInfo[0]), attrDims);
    528                    if (j >= 0)
    529                        attr.setProperty("field", memberNames[j]);
    530                    attributeList.add(attr);
    531
    532                    Object buf = null;
    533                    try {
    534                        buf = H4Datatype.allocateArray(attrInfo[0], attrInfo[1]);
    535                    }
    536                    catch (OutOfMemoryError e) {
    537                        log.debug("getMetadata(): out of memory: ", e);
    538                        buf = null;
    539                    }
    540
    541                    try {
    542                        HDFLibrary.VSgetattr(id, j, i, buf);
    543                    }
    544                    catch (HDFException ex) {
    545                        log.debug("getMetadata(): attribute[{}] VSgetattr failure: ", i, ex);
    546                        buf = null;
    547                    }
    548
    549                    if (buf != null) {
    550                        if ((attrInfo[0] == HDFConstants.DFNT_CHAR) ||
    551                                (attrInfo[0] ==  HDFConstants.DFNT_UCHAR8)) {
    552                            buf = Dataset.byteToString((byte[])buf, attrInfo[1]);
    553                        }
    554
    555                        attr.setAttributeData(buf);
    556                        nleft--;
    557                    }
    558                } //  (int i=0; i<n; i++)
    559            } //  (int j=-1; j<numberOfMembers; j++)
    560        }
    561        catch (Exception ex) {
    562            log.debug("getMetadata(): failure: ", ex);
    563        }
    564        finally {
    565            close(id);
    566        }
    567
    568        // todo: We shall also load attributes of fields
    569
    570        return attributeList;
    571    }
    572
    573    // To do: Implementing DataFormat
    574    /**
    575     * Writes a specific piece of metadata (such as an attribute) into the file.
    576     *
    577     * If an HDF(4&amp;5) attribute exists in the file, this method updates its
    578     * value. If the attribute does not exist in the file, it creates the
    579     * attribute in the file and attaches it to the object. It will fail to
    580     * write a new attribute to the object where an attribute with the same name
    581     * already exists. To update the value of an existing attribute in the file,
    582     * one needs to get the instance of the attribute by getMetadata(), change
    583     * its values, then use writeMetadata() to write the value.
    584     *
    585     * @param info
    586     *            the metadata to write.
    587     *
    588     * @throws Exception
    589     *             if the metadata can not be written
    590     */
    591    @Override
    592    @SuppressWarnings({"rawtypes", "unchecked"})
    593    public void writeMetadata(Object info) throws Exception {
    594        // only attribute metadata is supported.
    595        if (!(info instanceof Attribute)) {
    596            log.debug("writeMetadata(): Object not an H4Attribute");
    597            return;
    598        }
    599
    600        try {
    601            getFileFormat().writeAttribute(this, (H4ScalarAttribute)info, true);
    602
    603            if (attributeList == null)
    604                attributeList = new Vector();
    605
    606            attributeList.add(info);
    607            nAttributes = attributeList.size();
    608        }
    609        catch (Exception ex) {
    610            log.trace("writeMetadata(): failure: ", ex);
    611        }
    612    }
    613
    614    /**
    615     * Deletes an existing piece of metadata from this object.
    616     *
    617     * @param info
    618     *            the metadata to delete.
    619     *
    620     * @throws HDFException
    621     *             if the metadata can not be removed
    622     */
    623    @Override
    624    public void removeMetadata(Object info) throws HDFException {
    625        log.trace("removeMetadata(): disabled");
    626    }
    627
    628    /**
    629     * Updates an existing piece of metadata attached to this object.
    630     *
    631     * @param info
    632     *            the metadata to update.
    633     *
    634     * @throws Exception
    635     *             if the metadata can not be updated
    636     */
    637    @Override
    638    public void updateMetadata(Object info) throws Exception {
    639        log.trace("updateMetadata(): disabled");
    640    }
    641
    642    // Implementing DataFormat
    643    @Override
    644    public long open() {
    645        // try to open with write permission
    646        long vsid = -1;
    647        try {
    648            vsid = HDFLibrary.VSattach(getFID(), (int)oid[1], "w");
    649        }
    650        catch (HDFException ex) {
    651            log.debug("open(w): VSattach failure: ", ex);
    652            vsid = -1;
    653        }
    654
    655        // try to open with read-only permission
    656        if (vsid < 0) {
    657            try {
    658                vsid = HDFLibrary.VSattach(getFID(), (int)oid[1], "r");
    659            }
    660            catch (HDFException ex) {
    661                log.debug("open(r): VSattach failure: ", ex);
    662                vsid = -1;
    663            }
    664            log.debug("open(r): VSattach vsid: {}", vsid);
    665        }
    666
    667        return vsid;
    668    }
    669
    670    // Implementing DataFormat
    671    @Override
    672    public void close(long vsid) {
    673        try {
    674            HDFLibrary.VSdetach(vsid);
    675        }
    676        catch (Exception ex) {
    677            log.debug("close(): VSdetach failure: ", ex);
    678        }
    679    }
    680
    681    /**
    682     * Initializes the H4Vdata such as dimension sizes of this dataset.
    683     */
    684    @Override
    685    public void init() {
    686        if (inited) {
    687            log.trace("init(): Already initialized");
    688            return; // already called. Initialize only once
    689        }
    690
    691        long id = open();
    692        if (id < 0) {
    693            log.debug("init(): Invalid VData ID");
    694            return;
    695        }
    696
    697        try {
    698            numberOfMembers = HDFLibrary.VFnfields(id);
    699            numberOfRecords = HDFLibrary.VSelts(id);
    700        }
    701        catch (HDFException ex) {
    702            numberOfMembers = 0;
    703            numberOfRecords = 0;
    704        }
    705
    706        //        Still need to get information if there is no record, see bug 1738
    707        //        if ((numberOfMembers <=0) || (numberOfRecords <= 0)) {
    708        //            // no table field is defined or no records
    709        //            close(id);
    710        //            return;
    711        //        }
    712
    713        // a Vdata table is an one dimension array of records.
    714        // each record has the same fields
    715        rank = 1;
    716        dims = new long[1];
    717        dims[0] = numberOfRecords;
    718        selectedDims = new long[1];
    719        selectedDims[0] = numberOfRecords;
    720        selectedIndex[0] = 0;
    721        startDims = new long[1];
    722        startDims[0] = 0;
    723
    724        memberNames = new String[numberOfMembers];
    725        memberTIDs = new long[numberOfMembers];
    726        memberTypes = new Datatype[numberOfMembers];
    727        memberOrders = new int[numberOfMembers];
    728        isMemberSelected = new boolean[numberOfMembers];
    729
    730        try {
    731            datatype = new H4Datatype(Datatype.CLASS_COMPOUND, -1, Datatype.NATIVE, Datatype.NATIVE);
    732        }
    733        catch (Exception ex) {
    734            log.debug("init(): failed to create compound datatype for VData");
    735            datatype = null;
    736        }
    737
    738        for (int i = 0; i < numberOfMembers; i++) {
    739            isMemberSelected[i] = true;
    740            try {
    741                memberNames[i] = HDFLibrary.VFfieldname(id, i);
    742                memberTIDs[i] = HDFLibrary.VFfieldtype(id, i);
    743                try {
    744                    memberTypes[i] = new H4Datatype(memberTIDs[i]);
    745                }
    746                catch (Exception ex) {
    747                    log.debug("init(): failed to create datatype for member[{}]: ", i, ex);
    748                    memberTypes[i] = null;
    749                }
    750                // mask off the litend bit
    751                memberTIDs[i] = memberTIDs[i] & (~HDFConstants.DFNT_LITEND);
    752                memberOrders[i] = HDFLibrary.VFfieldorder(id, i);
    753                log.trace("init():{}> isMemberSelected[i]={} memberNames[i]={} memberTIDs[i]={} memberOrders[i]={}", i, isMemberSelected[i], memberNames[i], memberTIDs[i], memberOrders[i]);
    754
    755                /*
    756                 * NOTE: An ugly workaround to get HDF4 "compound" datatypes to work correctly.
    757                 */
    758                if (datatype != null) {
    759                    datatype.getCompoundMemberNames().add(memberNames[i]);
    760                    datatype.getCompoundMemberTypes().add(memberTypes[i]);
    761                }
    762            }
    763            catch (HDFException ex) {
    764                log.debug("init(): member[{}]: ", i, ex);
    765                continue;
    766            }
    767        } //  (int i=0; i<numberOfMembers; i++)
    768
    769        inited = true;
    770
    771        close(id);
    772    }
    773
    774    /**
    775     * Returns the number of records.
    776     *
    777     * @return the number of records
    778     */
    779    public int getRecordCount() {
    780        return numberOfRecords;
    781    }
    782
    783    /**
    784     * Returns the number of fields.
    785     *
    786     * @return the number of fields
    787     */
    788    public int getFieldCount() {
    789        return numberOfMembers;
    790    }
    791
    792    /**
    793     * Returns the orders of fields
    794     *
    795     * @return the orders of fields
    796     */
    797    public int[] getFieldOrders() {
    798        return memberOrders;
    799    }
    800
    801    //Implementing DataFormat
    802    /**
    803     * Retrieves the object's metadata, such as attributes, from the file.
    804     *
    805     * Metadata, such as attributes, is stored in a List.
    806     *
    807     * @param attrPropList
    808     *             the list of properties to get
    809     *
    810     * @return the list of metadata objects.
    811     *
    812     * @throws Exception
    813     *             if the metadata can not be retrieved
    814     */
    815    @SuppressWarnings("rawtypes")
    816    public List getMetadata(int... attrPropList) throws Exception {
    817        throw new UnsupportedOperationException("getMetadata(int... attrPropList) is not supported");
    818    }
    819
    820    @Override
    821    public Dataset copy(Group pgroup, String name, long[] dims, Object data) throws Exception {
    822        throw new UnsupportedOperationException("Writing a vdata to a new dataset is not implemented.");
    823    }
    824}