    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;
    016
    017import java.io.File;
    018import java.util.Enumeration;
    019import java.util.Hashtable;
    020import java.util.Iterator;
    021import java.util.Map;
    022import java.util.StringTokenizer;
    023import java.util.Vector;
    024
    025import org.slf4j.Logger;
    026import org.slf4j.LoggerFactory;
    027
    028/**
    029 * FileFormat defines general interfaces for working with files whose data is
    030 * organized according to a supported format.
    031 *
    032 * FileFormat is a pluggable component. New implementing classes of FileFormat
    033 * can be added to the list of supported file formats. Current implementing
    034 * classes include H5File and H4File. By default, H5File and H4File are added to
    035 * the list of supported file formats maintained by the static FileFormat
    036 * instance.
    037 *
    038 * <pre>
    039 *                                    FileFormat
    040 *                       _________________|_________________
    041 *                       |                |                |
    042 *                     H5File          H4File           Other...
    043 * </pre>
    044 *
    045 * A FileFormat instance may exist without being associated with a given file. A
    046 * FileFormat instance may be associated with a file that is not open for
    047 * access. Most typically, a FileFormat instance is used to open the associated
    048 * file and perform operations such as retrieval and manipulation (if the file
    049 * access is read-write) of the file structure and objects.
    050 *
    051 * @author Peter X. Cao
    052 * @version 2.4 9/4/2007
    053 */
    054public abstract class FileFormat extends File {
    055    private static final long                    serialVersionUID   = -4700692313888420796L;
    056
    057    private static final Logger log = LoggerFactory.getLogger(FileFormat.class);
    058
    059    /***************************************************************************
    060     * File access flags used in calls to createInstance( String, flag );
    061     **************************************************************************/
    062
    063    /**
    064     * File first time access flag for open file. With this access flag, added
    065     * to the regular value, indicates this file has no existing state.
    066     *
    067     */
    068    public static final int                      OPEN_NEW           = 1;
    069
    070    /**
    071     * File access flag for read-only permission. With this access flag,
    072     * modifications to the file will not be allowed.
    073     *
    074     * @see #createInstance(String, int )
    075     */
    076    public static final int                      READ               = 2;
    077
    078    /**
    079     * File access flag for read/write permission. With this access flag,
    080     * modifications to the file will be allowed. Behavior if the file does not
    081     * exist or cannot be opened for read/write access depends on the
    082     * implementing class.
    083     *
    084     * @see #createInstance(String, int)
    085     */
    086    public static final int                      WRITE              = 4;
    087
    088    /**
    089     * File access flag for creating/truncating with read-write permission. If
    090     * the file already exists, it will be truncated when opened. With this
    091     * access flag, modifications to the file will be allowed. Behavior if file
    092     * can't be created, or if it exists but can't be opened for read/write
    093     * access, depends on the implementing class.
    094     *
    095     * @see #createInstance(String, int )
    096     */
    097    public static final int                      CREATE             = 8;
    098
    099    /**
    100     * File access flag for multi-read-only permission. With this access flag,
    101     * modifications to the file will not be allowed.
    102     *
    103     * @see #createInstance(String, int )
    104     */
    105    public static final int                      MULTIREAD          = 80;
    106
    107    /***************************************************************************
    108     * File creation flags used in calls to createFile( String, flag );
    109     **************************************************************************/
    110
    111    /**
    112     * Flag for creating/truncating a file. If the file already exists, it will
    113     * be truncated when opened. If the file does not exist, it will be created.
    114     * Modifications to the file will be allowed.
    115     *
    116     * @see #createFile(String, int )
    117     */
    118    public static final int                      FILE_CREATE_DELETE = 10;
    119
    120    /**
    121     * Flag for creating/opening a file. If the file already exists, it will be
    122     * opened without changing the existing contents. If the file does not
    123     * exist, it will be created. Modifications to the file will be allowed.
    124     *
    125     * @see #createFile(String, int )
    126     */
    127    public static final int                      FILE_CREATE_OPEN   = 20;
    128
    129    /**
    130     * Flag to indicate if the earliest version of library is used when creating
    131     * a new file.
    132     *
    133     * @see #createFile(String, int )
    134     */
    135    public static final int                      FILE_CREATE_EARLY_LIB   = 40;
    136
    137
    138    /***************************************************************************
    139     * Keys and fields related to supported file formats.
    140     **************************************************************************/
    141
    142    /** Key for HDF4 file format. */
    143    public static final String                   FILE_TYPE_HDF4     = "HDF4";
    144
    145    /** Key for HDF5 file format. */
    146    public static final String                   FILE_TYPE_HDF5     = "HDF5";
    147
    148    /** Key for NetCDF file format. */
    149    public static final String                   FILE_TYPE_NC3      = "NetCDF3";
    150
    151    /**
    152     * A separator that separates file name and object name.
    153     *
    154     * @see hdf.object.FileFormat#getHObject(String)
    155     */
    156    public static final String                   FILE_OBJ_SEP       = "://";
    157
    158    /**
    159     * FileList keeps a list of supported FileFormats. This list can be updated
    160     * and queried at runtime.
    161     *
    162     * @see #addFileFormat(String,FileFormat)
    163     * @see #getFileFormat(String)
    164     * @see #getFileFormatKeys()
    165     * @see #getFileFormats()
    166     * @see #removeFileFormat(String)
    167     */
    168    private static final Map<String, FileFormat> FileList = new Hashtable<>(10);
    169
    170    /**
    171     * A list of file extensions for the supported file formats. This list of
    172     * file extensions is not integrated with the supported file formats kept in
    173     * FileList, but is provided as a convenience for applications who may
    174     * choose to process only those files with recognized extensions.
    175     */
    176    private static String extensions         = "hdf, h4, hdf5, h5, nc, fits";
    177
    178    /***************************************************************************
    179     * Sizing information and class metadata
    180     **************************************************************************/
    181
    182    /**
    183     * Current Java applications, such as HDFView, cannot handle files with
    184     * large numbers of objects due to JVM memory limitations. For example,
    185     * 1,000,000 objects is too many. max_members is defined so that
    186     * applications such as HDFView will load up to <i>max_members</i> objects
    187     * starting with the <i>start_members</i> -th object. The implementing class
    188     * has freedom in its interpretation of how to "count" objects in the file.
    189     */
    190    private int                                  max_members        = 10000;      // 10,000 by default
    191    /**
    192     * The start number for max_members .
    193     */
    194    private int                                  start_members      = 0;          // 0 by default
    195
    196    /**
    197     * File identifier. -1 indicates the file is not open.
    198     */
    199    protected long                                fid                = -1;
    200
    201    /**
    202     * The absolute pathname (path+name) of the file.
    203     */
    204    protected String                             fullFileName       = null;
    205
    206    /**
    207     * Flag indicating if the file access is read-only.
    208     */
    209    protected boolean                            isReadOnly         = false;
    210
    211    /***************************************************************************
    212     * Class initialization method
    213     **************************************************************************/
    214
    215    /**
    216     * By default, HDF4 and HDF5 file formats are added to the supported formats
    217     * list.
    218     */
    219    static {
    220        // add HDF4 to default modules
    221        if (FileFormat.getFileFormat(FILE_TYPE_HDF4) == null) {
    222            try {
    223                @SuppressWarnings("rawtypes")
    224                Class fileclass = Class.forName("hdf.object.h4.H4File");
    225                FileFormat fileformat = (FileFormat) fileclass.newInstance();
    226                if (fileformat != null) {
    227                    FileFormat.addFileFormat(FILE_TYPE_HDF4, fileformat);
    228                    log.debug("FILE_TYPE_HDF4 file format added");
    229                }
    230            }
    231            catch (Exception err) {
    232                log.debug("FILE_TYPE_HDF4 instance failure: ", err);
    233            }
    234        }
    235
    236        // add HDF5 to default modules
    237        if (FileFormat.getFileFormat(FILE_TYPE_HDF5) == null) {
    238            try {
    239                @SuppressWarnings("rawtypes")
    240                Class fileclass = Class.forName("hdf.object.h5.H5File");
    241                FileFormat fileformat = (FileFormat) fileclass.newInstance();
    242                if (fileformat != null) {
    243                    FileFormat.addFileFormat(FILE_TYPE_HDF5, fileformat);
    244                    log.debug("FILE_TYPE_HDF5 file format added");
    245                }
    246            }
    247            catch (Exception err) {
    248                log.debug("FILE_TYPE_HDF5 instance failure: ", err);
    249            }
    250        }
    251
    252        // add NetCDF to default modules
    253        if (FileFormat.getFileFormat(FILE_TYPE_NC3) == null) {
    254            try {
    255                @SuppressWarnings("rawtypes")
    256                Class fileclass = Class.forName("hdf.object.nc2.NC2File");
    257                FileFormat fileformat = (FileFormat) fileclass.newInstance();
    258                if (fileformat != null) {
    259                    FileFormat.addFileFormat(FILE_TYPE_NC3, fileformat);
    260                    log.debug("NetCDF3 file format added");
    261                }
    262            }
    263            catch (Exception err) {
    264                log.debug("NetCDF3 instance failure: ", err);
    265            }
    266        }
    267
    268        // add FITS to default modules
    269        if (FileFormat.getFileFormat("FITS") == null) {
    270            try {
    271                @SuppressWarnings("rawtypes")
    272                Class fileclass = Class.forName("hdf.object.fits.FitsFile");
    273                FileFormat fileformat = (FileFormat) fileclass.newInstance();
    274                if (fileformat != null) {
    275                    FileFormat.addFileFormat("FITS", fileformat);
    276                    log.debug("Fits file format added");
    277                }
    278            }
    279            catch (Exception err) {
    280                log.debug("FITS instance failure: ", err);
    281            }
    282        }
    283
    284    }
    285
    286    /***************************************************************************
    287     * Constructor
    288     **************************************************************************/
    289
    290    /**
    291     * Creates a new FileFormat instance with the given filename.
    292     *
    293     * The filename in this method call is equivalent to the pathname in the
    294     * java.io.File class. The filename is converted into an abstract pathname
    295     * by the File class.
    296     *
    297     * Typically this constructor is not called directly, but is called by a
    298     * constructor of an implementing class. Applications most frequently use
    299     * the <i>createFile()</i>, <i>createInstance()</i>, or <i>getInstance()</i>
    300     * methods to generate a FileFormat instance with an associated filename.
    301     *
    302     * The file is not opened by this call. The read-only flag is set to false
    303     * by this call.
    304     *
    305     * @param filename
    306     *            The filename; a pathname string.
    307     * @throws NullPointerException
    308     *             If the <code>filename</code> argument is <code>null</code>.
    309     * @see java.io.File#File(String)
    310     * @see #createFile(String, int)
    311     * @see #createInstance(String, int)
    312     * @see #getInstance(String)
    313     */
    314    public FileFormat(String filename) {
    315        super(filename);
    316
    317        fullFileName = filename;
    318
    319        if ((filename != null) && (filename.length() > 0)) {
    320            try {
    321                fullFileName = this.getAbsolutePath();
    322            }
    323            catch (Exception ex) {
    324                log.debug("File {} getAbsolutePath failure: ", filename, ex);
    325            }
    326        }
    327        isReadOnly = false;
    328        log.trace("fullFileName={} isReadOnly={}", fullFileName, isReadOnly);
    329    }
    330
    331    /***************************************************************************
    332     * Class methods
    333     **************************************************************************/
    334
    335    /**
    336     * Adds a FileFormat with specified key to the list of supported formats.
    337     *
    338     * This method allows a new FileFormat, tagged with an identifying key, to
    339     * be added dynamically to the list of supported File Formats. Using it,
    340     * applications can add new File Formats at runtime.
    341     *
    342     * For example, to add a new File Format with the key "xyz" that is
    343     * implemented by the class xyzFile in the package companyC.files, an
    344     * application would make the following calls:
    345     *
    346     * <pre>
    347     *    Class fileClass = Class.forName( "companyC.files.xyzFile" );
    348     *    FileFormat ff = (FileFormat) fileClass.newInstance();
    349     *    if ( ff != null ) {
    350     *       ff.addFileFormat ("xyz", ff )
    351     *    }
    352     * </pre>
    353     *
    354     * If either <code>key</code> or <code>fileformat</code> are
    355     * <code>null</code>, or if <code>key</code> is already in use, the method
    356     * returns without updating the list of supported File Formats.
    357     *
    358     * @param key
    359     *            A string that identifies the FileFormat.
    360     * @param fileformat
    361     *            An instance of the FileFormat to be added.
    362     * @see #getFileFormat(String)
    363     * @see #getFileFormatKeys()
    364     * @see #getFileFormats()
    365     * @see #removeFileFormat(String)
    366     */
    367    public static final void addFileFormat(String key, FileFormat fileformat) {
    368        if ((fileformat == null) || (key == null))
    369            return;
    370
    371        key = key.trim();
    372
    373        if (!FileList.containsKey(key))
    374            FileList.put(key, fileformat);
    375    }
    376
    377    /**
    378     * Returns the FileFormat with specified key from the list of supported
    379     * formats.
    380     *
    381     * This method returns a FileFormat instance, as identified by an
    382     * identifying key, from the list of supported File Formats.
    383     *
    384     * If the specified key is in the list of supported formats, the instance of
    385     * the associated FileFormat object is returned. If the specified key is not
    386     * in the list of supported formats, <code>null</code> is returned.
    387     *
    388     * @param key
    389     *            A string that identifies the FileFormat.
    390     * @return The FileFormat that matches the given key, or <code>null</code>
    391     *         if the key is not found in the list of supported File Formats.
    392     * @see #addFileFormat(String,FileFormat)
    393     * @see #getFileFormatKeys()
    394     * @see #getFileFormats()
    395     * @see #removeFileFormat(String)
    396     */
    397    public static final FileFormat getFileFormat(String key) {
    398        return FileList.get(key);
    399    }
    400
    401    /**
    402     * Returns an Enumeration of keys for all supported formats.
    403     *
    404     * This method returns an Enumeration containing the unique keys (Strings)
    405     * for the all File Formats in the list of supported File Formats.
    406     *
    407     * @return An Enumeration of keys that are in the list of supported formats.
    408     * @see #addFileFormat(String,FileFormat)
    409     * @see #getFileFormat(String)
    410     * @see #getFileFormats()
    411     * @see #removeFileFormat(String)
    412     */
    413    @SuppressWarnings("rawtypes")
    414    public static final Enumeration getFileFormatKeys() {
    415        return ((Hashtable) FileList).keys();
    416    }
    417
    418    /**
    419     * Returns an array of supported FileFormat instances.
    420     *
    421     * This method returns an array of FileFormat instances that appear in the
    422     * list of supported File Formats.
    423     *
    424     * If the list of supported formats is empty, <code>null</code> is returned.
    425     *
    426     * @return An array of all FileFormat instances in the list of supported
    427     *         File Formats, or <code>null</code> if the list is empty.
    428     * @see #addFileFormat(String,FileFormat)
    429     * @see #getFileFormat(String)
    430     * @see #getFileFormatKeys()
    431     * @see #removeFileFormat(String)
    432     */
    433    @SuppressWarnings("rawtypes")
    434    public static final FileFormat[] getFileFormats() {
    435        int n = FileList.size();
    436        if (n <= 0)
    437            return null;
    438
    439        int i = 0;
    440        FileFormat[] fileformats = new FileFormat[n];
    441        Enumeration<?> local_enum = ((Hashtable) FileList).elements();
    442        while (local_enum.hasMoreElements())
    443            fileformats[i++] = (FileFormat) local_enum.nextElement();
    444
    445        return fileformats;
    446    }
    447
    448    /**
    449     * Removes a FileFormat from the list of supported formats.
    450     *
    451     * This method removes a FileFormat, as identified by the specified key,
    452     * from the list of supported File Formats.
    453     *
    454     * If the specified key is in the list of supported formats, the instance of
    455     * the FileFormat object that is being removed from the list is returned. If
    456     * the key is not in the list of supported formats, <code>null</code> is
    457     * returned.
    458     *
    459     * @param key
    460     *            A string that identifies the FileFormat to be removed.
    461     * @return The FileFormat that is removed, or <code>null</code> if the key
    462     *         is not found in the list of supported File Formats.
    463     * @see #addFileFormat(String,FileFormat)
    464     * @see #getFileFormat(String)
    465     * @see #getFileFormatKeys()
    466     * @see #getFileFormats()
    467     */
    468    public static final FileFormat removeFileFormat(String key) {
    469        return FileList.remove(key);
    470    }
    471
    472    /**
    473     * Adds file extension(s) to the list of file extensions for supported file
    474     * formats.
    475     *
    476     * Multiple extensions can be included in the single parameter if they are
    477     * separated by commas.
    478     *
    479     * The list of file extensions updated by this call is not linked with
    480     * supported formats that implement FileFormat objects. The file extension
    481     * list is maintained for the benefit of applications that may choose to
    482     * recognize only those files with extensions that appear in the list of
    483     * file extensions for supported file formats.
    484     *
    485     * By default, the file extensions list includes: "hdf, h4, hdf5, h5"
    486     *
    487     * @param extension
    488     *            The file extension(s) to add.
    489     * @see #addFileFormat(String,FileFormat)
    490     * @see #getFileExtensions()
    491     */
    492    public static final void addFileExtension(String extension) {
    493        if ((extensions == null) || (extensions.length() <= 0))
    494            extensions = extension;
    495
    496        StringTokenizer currentExt = new StringTokenizer(extensions, ",");
    497        Vector<String> tokens = new Vector<>(currentExt.countTokens() + 5);
    498
    499        while (currentExt.hasMoreTokens())
    500            tokens.add(currentExt.nextToken().trim().toLowerCase());
    501
    502        currentExt = new StringTokenizer(extension, ",");
    503        String ext = null;
    504        while (currentExt.hasMoreTokens()) {
    505            ext = currentExt.nextToken().trim().toLowerCase();
    506            if (tokens.contains(ext))
    507                continue;
    508
    509            extensions = extensions + ", " + ext;
    510        }
    511
    512        tokens.setSize(0);
    513    }
    514
    515    /**
    516     * Returns a list of file extensions for all supported file formats.
    517     *
    518     * The extensions in the returned String are separates by commas:
    519     * "hdf, h4, hdf5, h5"
    520     *
    521     * It is the responsibility of the application to update the file extension
    522     * list using {@link #addFileExtension(String)} when new FileFormat
    523     * implementations are added.
    524     *
    525     * @return A list of file extensions for all supported file formats.
    526     * @see #addFileExtension(String)
    527     */
    528    public static final String getFileExtensions() {
    529        return extensions;
    530    }
    531
    532    /**
    533     * Creates a FileFormat instance for the specified file.
    534     *
    535     * This method checks the list of supported file formats to find one that
    536     * matches the format of the specified file. If a match is found, the method
    537     * returns an instance of the associated FileFormat object. If no match is
    538     * found, <code>null</code> is returned.
    539     *
    540     * For example, if "test_hdf5.h5" is an HDF5 file,
    541     * FileFormat.getInstance("test_hdf5.h5") will return an instance of H5File.
    542     *
    543     * The file is not opened as part of this call. Read/write file access is
    544     * associated with the FileFormat instance if the matching file format
    545     * supports read/write access. Some file formats only support read access.
    546     *
    547     * @param filename
    548     *            A valid file name, with a relative or absolute path.
    549     * @return An instance of the matched FileFormat; <code>null</code> if no
    550     *         match.
    551     * @throws IllegalArgumentException
    552     *             If the <code>filename</code> argument is <code>null</code> or
    553     *             does not specify an existing file.
    554     * @throws Exception
    555     *             If there are problems creating the new instance.
    556     * @see #createFile(String, int)
    557     * @see #createInstance(String, int)
    558     * @see #getFileFormats()
    559     */
    560    @SuppressWarnings("rawtypes")
    561    public static final FileFormat getInstance(String filename) throws Exception {
    562        if ((filename == null) || (filename.length() <= 0))
    563            throw new IllegalArgumentException("Invalid file name: " + filename);
    564
    565        if (!(new File(filename)).exists())
    566            throw new IllegalArgumentException("File " + filename + " does not exist.");
    567
    568        FileFormat fileFormat = null;
    569        FileFormat knownFormat = null;
    570        Enumeration<?> elms = ((Hashtable) FileList).elements();
    571
    572        while (elms.hasMoreElements()) {
    573            knownFormat = (FileFormat) elms.nextElement();
    574            if (knownFormat.isThisType(filename)) {
    575                try {
    576                    fileFormat = knownFormat.createInstance(filename, WRITE);
    577                }
    578                catch (Exception ex) {
    579                    log.debug("File {} createInstance failure: ", filename, ex);
    580                }
    581                break;
    582            }
    583        }
    584
    585        return fileFormat;
    586    }
    587
    588    /***************************************************************************
    589     * Implementation Class methods. These methods are related to the
    590     * implementing FileFormat class, but not to a particular instance of that
    591     * class. Since we can't override class methods (they can only be shadowed
    592     * in Java), these are instance methods.
    593     *
    594     * The non-abstract methods just throw an exception indicating that the
    595     * implementing class doesn't support the functionality.
    596     **************************************************************************/
    597
    598    /**
    599     * Returns the version of the library for the implementing FileFormat class.
    600     *
    601     * The implementing FileFormat classes have freedom in how they obtain or
    602     * generate the version number that is returned by this method. The H5File
    603     * and H4File implementations query the underlying HDF libraries and return
    604     * the reported version numbers. Other implementing classes may generate the
    605     * version string directly within the called method.
    606     *
    607     * @return The library version.
    608     */
    609    public abstract String getLibversion();
    610
    611    /**
    612     * Checks if the class implements the specified FileFormat.
    613     *
    614     * The Java "instanceof" operation is unable to check if an object is an
    615     * instance of a FileFormat that is loaded at runtime. This method provides
    616     * the "instanceof" functionality, and works for implementing classes that
    617     * are loaded at runtime.
    618     *
    619     * This method lets applications that only access the abstract object layer
    620     * determine the format of a given instance of the abstract class.
    621     *
    622     * For example, HDFView uses the following code to determine if a file is an
    623     * HDF5 file:
    624     *
    625     * <pre>
    626     * FileFormat h5F = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5);
    627     * HObject hObject = viewer.getTreeView().getCurrentObject();
    628     * FileFormat thisF = hObject.getFileFormat();
    629     * boolean isH5 = h5F.isThisType(thisF);
    630     * </pre>
    631     *
    632     * @param fileFormat
    633     *            The FileFormat to be checked.
    634     * @return True if this instance implements the specified FileFormat;
    635     *         otherwise returns false.
    636     * @see #isThisType(String)
    637     */
    638    public abstract boolean isThisType(FileFormat fileFormat);
    639
    640    /**
    641     * Checks if the implementing FileFormat class matches the format of the
    642     * specified file.
    643     *
    644     * For example, if "test.h5" is an HDF5 file, the first call to isThisType()
    645     * in the code fragment shown will return <code>false</code>, and the second
    646     * call will return <code>true</code>.
    647     *
    648     * <pre>
    649     * FileFormat ncF = FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3);
    650     * FileFormat h4F = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4);
    651     * FileFormat h5F = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5);
    652     * boolean isH4 = h4F.isThisType(&quot;test.h5&quot;); // false
    653     *                                                                                                                                                                                   boolean isH5 = h5F.isThisType(&quot;test.h5&quot;); // true
    654     * </pre>
    655     *
    656     * @param filename
    657     *            The name of the file to be checked.
    658     * @return True if the format of the file matches the format of this
    659     *         instance; otherwise returns false.
    660     * @see #isThisType(FileFormat)
    661     */
    662    public abstract boolean isThisType(String filename);
    663
    664    /**
    665     * Creates a file with the specified name and returns a new FileFormat
    666     * implementation instance associated with the file.
    667     *
    668     * This method creates a file whose format is the same as that of the
    669     * implementing class. An instance of the FileFormat implementing class is
    670     * created and associated with the file. That instance is returned by the
    671     * method.
    672     *
    673     * The filename in this method call is equivalent to the pathname in the
    674     * java.io.File class. The filename is converted into an abstract pathname
    675     * by the File class.
    676     *
    677     * A flag controls the behavior if the named file already exists. The flag
    678     * values and corresponding behaviors are:
    679     * <ul>
    680     * <li>FILE_CREATE_DELETE: Create a new file or truncate an existing one.
    681     * <li>FILE_CREATE_OPEN: Create a new file or open an existing one.
    682     * </ul>
    683     *
    684     * If the flag is FILE_CREATE_DELETE, the method will create a new file or
    685     * truncate an existing file. If the flag is FILE_CREATE_OPEN and the file
    686     * does not exist, the method will create a new file.
    687     *
    688     * This method does not open the file for access, nor does it confirm that
    689     * the file can later be opened read/write. The file open is carried out by
    690     * the <i>open()</i> call.
    691     *
    692     * @param filename
    693     *            The filename; a pathname string.
    694     * @param createFlag
    695     *            The creation flag, which determines behavior when the file
    696     *            already exists. Acceptable values are
    697     *            <code>FILE_CREATE_DELETE</code> and
    698     *            <code>FILE_CREATE_OPEN</code>.
    699     * @throws NullPointerException
    700     *             If the <code>filename</code> argument is <code>null</code>.
    701     * @throws UnsupportedOperationException
    702     *             If the implementing class does not support the file creation operation.
    703     * @throws Exception
    704     *             If the file cannot be created or if the creation flag has an
    705     *             unexpected value. The exceptions thrown vary depending on the
    706     *             implementing class.
    707     * @see #createInstance(String, int)
    708     * @see #getInstance(String)
    709     * @see #open()
    710     *
    711     * @return the FileFormat instance.
    712     */
    713    public FileFormat createFile(String filename, int createFlag) throws Exception {
    714        // If the implementing subclass doesn't have this method then that
    715        // format doesn't support File Creation and we throw an exception.
    716        throw new UnsupportedOperationException("FileFormat FileFormat.createFile(...) is not implemented.");
    717    }
    718
    719    /**
    720     * Creates a FileFormat implementation instance with specified filename and
    721     * access.
    722     *
    723     * This method creates an instance of the FileFormat implementing class and
    724     * sets the filename and file access parameters.
    725     *
    726     * The filename in this method call is equivalent to the pathname in the
    727     * java.io.File class. The filename is converted into an abstract pathname
    728     * by the File class.
    729     *
    730     * The access parameter values and corresponding behaviors at file open:
    731     * <ul>
    732     * <li>READ: Read-only access. Fail if file doesn't exist.
    733     * <li>SWMR: Read-only access. Fail if file doesn't exist.
    734     * <li>WRITE: Read/Write access. Behavior if file doesn't exist or can't be
    735     * opened for read/write access depends on the implementing class.
    736     * <li>CREATE: Read/Write access. Create a new file or truncate an existing
    737     * one. Behavior if file can't be created, or if it exists but can't be
    738     * opened read/write depends on the implementing class.
    739     * </ul>
    740     *
    741     * Some FileFormat implementing classes may only support READ access and
    742     * will use READ regardless of the value specified in the call. Refer to the
    743     * implementing class documentation for details.
    744     *
    745     * This method does not open the file for access, nor does it confirm that
    746     * the file can later be opened read/write or created. The file open is
    747     * carried out by the <i>open()</i> call.
    748     *
    749     * Example (without exception handling):
    750     *
    751     * <pre>
    752     * // Request the implementing class of FileFormat: H5File
    753     * FileFormat h5file = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5);
    754     *
    755     * // Create an instance of H5File object with read/write access
    756     * H5File test1 = (H5File) h5file.createInstance(&quot;test_hdf5.h5&quot;,
    757     *                                               FileFormat.WRITE);
    758     *
    759     * // Open the file and load the file structure; file id is returned.
    760     * int fid = test1.open();
    761     * </pre>
    762     *
    763     * @param filename
    764     *            The filename; a pathname string.
    765     * @param access
    766     *            The file access flag, which determines behavior when file is
    767     *            opened. Acceptable values are <code> READ, WRITE, </code> and
    768     *            <code>CREATE</code>.
    769     * @throws NullPointerException
    770     *             If the <code>filename</code> argument is <code>null</code>.
    771     * @throws Exception
    772     *             If the instance cannot be created or if the access flag has
    773     *             an unexpected value. The exceptions thrown vary depending on
    774     *             the implementing class.
    775     * @see #createFile(String, int)
    776     * @see #getInstance(String)
    777     * @see #open()
    778     *
    779     * @return the FileFormat instance.
    780     */
    781    public abstract FileFormat createInstance(String filename, int access) throws Exception;
    782
    783    // REVIEW DOCS for createInstance()
    784    // What if READ ONLY in implementation? What if file already open?
    785    // Can we doc exceptions better or in implementation methods?
    786
    787    /***************************************************************************
    788     * Final instance methods
    789     *
    790     * Related to a given instance of the class, but at the FileFormat level,
    791     * not at the implementing class level.
    792     **************************************************************************/
    793
    794    /**
    795     * Returns the absolute path for the file.
    796     *
    797     * For example, "/samples/hdf5_test.h5". If there is no file associated with
    798     * this FileFormat instance, <code>null</code> is returned.
    799     *
    800     * @return The full path (file path + file name) of the associated file, or
    801     *         <code>null</code> if there is no associated file.
    802     */
    803    public final String getFilePath() {
    804        return fullFileName;
    805    }
    806
    807    /**
    808     * Returns file identifier of open file associated with this instance.
    809     *
    810     * @return The file identifer, or -1 if there is no file open.
    811     */
    812    public final long getFID() {
    813        return fid;
    814    }
    815
    816    /**
    817     * Returns true if the file access is read-only.
    818     *
    819     * This method returns true if the file access is read-only. If the file
    820     * access is read-write, or if there is no file associated with the
    821     * FileFormat instance, false will be returned.
    822     *
    823     * Note that this method may return true even if the file is not open for
    824     * access when the method is called. The file access is set by the
    825     * <i>createFile()</i>, <i>createInstance()</i>, or <i>getInstance()</i>
    826     * call, and the file is opened for access by the <i>open()</i> call.
    827     *
    828     * @return True if the file access is read-only, otherwise returns false.
    829     * @see #createFile(String, int)
    830     * @see #createInstance(String, int)
    831     * @see #getInstance(String)
    832     * @see #open()
    833     */
    834    public final boolean isReadOnly() {
    835        return isReadOnly;
    836    }
    837
    838    /**
    839     * Sets the maximum number of objects to be loaded into memory.
    840     *
    841     * Current Java applications, such as HDFView, cannot handle files with
    842     * large numbers of objects due to JVM memory limitations. The maximum
    843     * number limits the number of objects that will be loaded for a given
    844     * FileFormat instance.
    845     *
    846     * The implementing FileFormat class has freedom in how it interprets the
    847     * maximum number. H5File, for example, will load the maximum number of
    848     * objects for each group in the file.
    849     *
    850     * @param n
    851     *            The maximum number of objects to be loaded into memory.
    852     * @see #getMaxMembers()
    853     * @see #setStartMembers(int)
    854     */
    855    public final void setMaxMembers(int n) {
    856        max_members = n;
    857    }
    858
    859    /**
    860     * Returns the maximum number of objects that can be loaded into memory.
    861     *
    862     * @return The maximum number of objects that can be loaded into memory.
    863     * @see #setMaxMembers(int)
    864     */
    865    public final int getMaxMembers() {
    866        if (max_members<0)
    867            return Integer.MAX_VALUE; // load the whole file
    868
    869        return max_members;
    870    }
    871
    872    /**
    873     * Sets the starting index of objects to be loaded into memory.
    874     *
    875     * The implementing FileFormat class has freedom in how it indexes objects
    876     * in the file.
    877     *
    878     * @param idx
    879     *            The starting index of the object to be loaded into memory
    880     * @see #getStartMembers()
    881     * @see #setMaxMembers(int)
    882     */
    883    public final void setStartMembers(int idx) {
    884        start_members = idx;
    885    }
    886
    887    /**
    888     * Returns the index of the starting object to be loaded into memory.
    889     *
    890     * @return The index of the starting object to be loaded into memory.
    891     * @see #setStartMembers(int)
    892     */
    893    public final int getStartMembers() {
    894        return start_members;
    895    }
    896
    897    /**
    898     * Returns the number of objects in memory.
    899     *
    900     * This method returns the total number of objects loaded into memory for
    901     * this FileFormat instance. The method counts the objects that are loaded,
    902     * which can take some time for a large number of objects.
    903     *
    904     * It is worth noting that the total number of objects in memory may be
    905     * different than the total number of objects in the file.
    906     *
    907     * Since implementing classes have freedom in how they interpret and use the
    908     * maximum number of members value, there may be differing numbers of
    909     * objects in memory in different implementation instances, even with the
    910     * same "use case".
    911     *
    912     * For example, say the use case is a file that contains 20,000 objects, the
    913     * maximum number of members for an instance is 10,000, and the start member
    914     * index is 1. There are 2 groups in the file. The root group contains
    915     * 10,500 objects and the group "/g1" contains 9,500 objects.
    916     *
    917     * In an implementation that limits the total number of objects loaded to
    918     * the maximum number of members, this method will return 10,000.
    919     *
    920     * In contrast, the H5File implementation loads up to the maximum number of
    921     * members objects for each group in the file. So, with our use case 10,000
    922     * objects will be loaded in the root group and 9,500 objects will be loaded
    923     * into group "/g1". This method will return the value 19,500, which exceeds
    924     * the maximum number of members value.
    925     *
    926     * @return The number of objects in memory.
    927     * @see #getMaxMembers()
    928     * @see #setMaxMembers(int)
    929     * @see #getStartMembers()
    930     * @see #setStartMembers(int)
    931     */
    932    public final int getNumberOfMembers() {
    933        HObject rootObject = getRootObject();
    934
    935        // Account for root object
    936        if (rootObject != null)
    937            return ((Group) rootObject).depthFirstMemberList().size() + 1;
    938
    939        return 0;
    940    }
    941
    942    /***************************************************************************
    943     * Abstract Instance methods
    944     *
    945     * These methods are related to the Implementing FileFormat class and to
    946     * particular instances of objects with those classes.
    947     **************************************************************************/
    948
    949    /**
    950     * Opens file and returns a file identifier.
    951     *
    952     * This method uses the <code>filename</code> and <code>access</code>
    953     * parameters specified in the <i>createFile()</i>, <i>createInstance()</i>,
    954     * or <i>getInstance()</i> call to open the file. It returns the file
    955     * identifier if successful, or a negative value in case of failure.
    956     *
    957     * The method also loads the file structure and basic information (name,
    958     * type) for data objects in the file into the FileFormat instance. It does
    959     * not load the contents of any data object.
    960     *
    961     * The structure of the file is stored in a tree starting from the root
    962     * object.
    963     *
    964     * @return File identifier if successful; otherwise -1.
    965     * @throws Exception
    966     *             If the file cannot be opened. The exceptions thrown vary
    967     *             depending on the implementing class.
    968     * @see #createFile(String, int)
    969     * @see #createInstance(String, int)
    970     * @see #getInstance(String)
    971     * @see #getRootObject()
    972     */
    973    public abstract long open() throws Exception;
    974
    975    /**
    976     * Closes file associated with this instance.
    977     *
    978     * This method closes the file associated with this FileFormat instance, as
    979     * well as all objects associated with the file.
    980     *
    981     * @throws Exception
    982     *             If the file or associated objects cannot be closed. The
    983     *             exceptions thrown vary depending on the implementing class.
    984     * @see #open()
    985     */
    986    public abstract void close() throws Exception;
    987
    988    // REVIEW DOCS for close()
    989    // What if we try to close a file whose fid is -1? Does this set fid to -1?
    990    // What if it's not open? What if no file? are structures & root object
    991    // still loaded?
    992    // Can we doc exceptions better or in implementation methods?
    993
    994    /**
    995     * Returns the root object for the file associated with this instance.
    996     *
    997     * The root object is an HObject that represents the root group of a
    998     * file. If the file has not yet been opened, or if there is no file
    999     * associated with this instance, <code>null</code> will be returned.
    1000     *
    1001     * Starting from the root, applications can descend through the tree
    1002     * structure and navigate among the file's objects. In the tree structure,
    1003     * internal items represent non-empty groups. Leaf items represent datasets,
    1004     * named datatypes, or empty groups.
    1005     *
    1006     * @return The root object of the file, or <code>null</code> if there is no
    1007     *         associated file or if the associated file has not yet been opened.
    1008     * @see #open()
    1009     */
    1010    public abstract HObject getRootObject();
    1011
    1012    /**
    1013     * Gets the HObject with the specified path from the file.
    1014     *
    1015     * This method returns the specified object from the file associated with
    1016     * this FileFormat instance.
    1017     *
    1018     * If the specified object is a group, groups and datasets that are members
    1019     * of the group will be accessible via the returned HObject instance. The
    1020     * exact contents of the returned HObject instance depends on whether or not
    1021     * {@link #open()} was called previously for this file.
    1022     * <ul>
    1023     * <li>If the file was opened prior to this method call, the complete tree
    1024     * of objects under the group will be accessible via the returned HObject
    1025     * instance.
    1026     * <li>If the file was not opened prior to this method call, only the
    1027     * members immediately under the group will be accessible via the returned
    1028     * HOBject instance.
    1029     * </ul>
    1030     *
    1031     * The decision to have different behaviors was made to give users some
    1032     * control over the "cost" of the method. In many cases, a user wants only
    1033     * one level of a tree, and the performance penalty for loading the entire
    1034     * hierarchy of objects in a large and complex file can be significant. In
    1035     * the case where <i>open()</i> has already been called, the HObject
    1036     * instances have already been created in memory and can be returned
    1037     * quickly. If <i>open()</i> has not been called, this method creates the
    1038     * HObject instances before returning the requested HObject.
    1039     *
    1040     * For example, say we have the following structure in our file:
    1041     *
    1042     * <pre>
    1043     *        /g0                      Group
    1044     *        /g0/dataset_comp         Dataset {50, 10}
    1045     *        /g0/dataset_int          Dataset {50, 10}
    1046     *        /g0/g00                  Group
    1047     *        /g0/g00/dataset_float    Dataset {50, 10}
    1048     *        /g0/g01                  Group
    1049     *        /g0/g01/dataset_string   Dataset {50, 10}
    1050     * </pre>
    1051     *
    1052     * <ul>
    1053     * <li>If <i>open()</i> is called before <i>get()</i>, the full structure of
    1054     * file is loaded into memory. The call <code>get("/g0")</code> returns the
    1055     * instance for /g0 with the information necessary to access
    1056     * /g0/dataset_comp, /g0/dataset_int, /g0/g00, /g0/g00/dataset_float,
    1057     * /g0/g01, and /g0/g01/dataset_string.
    1058     * <li>If <i>open()</i> is not called before <i>get()</i>, only the objects
    1059     * immediately under the specified group are accessible via the returned
    1060     * HObject instance. In this example, the call <code>get("/go")</code>
    1061     * returns the instance for /g0 with the information necessary to access
    1062     * /g0/dataset_comp, /g0/dataset_int, /g0/g00, and /g0/g01.
    1063     * </ul>
    1064     *
    1065     * @param path
    1066     *            Full path of the data object to be returned.
    1067     * @return The object if it exists in the file; otherwise <code>null</code>.
    1068     * @throws Exception
    1069     *             If there are unexpected problems in trying to retrieve the
    1070     *             object. The exceptions thrown vary depending on the
    1071     *             implementing class.
    1072     */
    1073    public abstract HObject get(String path) throws Exception;
    1074
    1075    // REVIEW DOCS for get(); What if no file associated w/ instance?
    1076    // Look at exceptions. Confirm example. Make sure perf tradeoffs
    1077    // documented properly.
    1078
    1079    /**
    1080     * Creates a named datatype in a file.
    1081     *
    1082     * The following code creates a named datatype in a file.
    1083     *
    1084     * <pre>
    1085     * H5File file = (H5File) h5file.createInstance(&quot;test_hdf5.h5&quot;, FileFormat.WRITE);
    1086     * H5Datatype dtype = file.createNamedDatatype(
    1087     *                             nativetype,
    1088     *                             &quot;Native Integer&quot;);
    1089     * </pre>
    1090     * @param tnative
    1091     *            the native datatype of the new datatype
    1092     * @param name
    1093     *            name of the datatype to create, e.g. "Native Integer".
    1094     * @return The new datatype if successful; otherwise returns null.
    1095     * @throws Exception
    1096     *             The exceptions thrown vary depending on the implementing class.
    1097     */
    1098    public Datatype createNamedDatatype(Datatype tnative, String name) throws Exception {
    1099        // If the implementing subclass doesn't have this method then that
    1100        // format doesn't support Named Datatypes and we throw an exception.
    1101        throw new UnsupportedOperationException("Datatype FileFormat.createNamedDatatype(...) is not implemented.");
    1102    }
    1103
    1104    // REVIEW DOCS for createDatatype(). Check and document exceptions.
    1105
    1106    /***************************************************************************
    1107     * Methods related to Datatypes and HObjects in the implementing FileFormat.
    1108     *
    1109     * Strictly speaking, these methods aren't related to FileFormat and the
    1110     * actions could be carried out through the HObject and Datatype classes.
    1111     * But, in some cases they allow a null input and expect the generated
    1112     * object to be of a type that has particular FileFormat. Therefore, we put
    1113     * them in the implementing FileFormat class so that we create the proper
    1114     * type of HObject... H5Group or H4Group for example.
    1115     *
    1116     * Here again, if there could be Implementation Class methods we'd use
    1117     * those. But, since we can't override class methods (they can only be
    1118     * shadowed in Java), these are instance methods.
    1119     *
    1120     * The non-abstract methods just throw an exception indicating that the
    1121     * implementing class doesn't support the functionality.
    1122     **************************************************************************/
    1123
    1124    /**
    1125     * Creates a new datatype in memory.
    1126     *
    1127     * The following code creates an instance of H5Datatype in memory.
    1128     *
    1129     * <pre>
    1130     * H5File file = (H5File) h5file.createInstance(&quot;test_hdf5.h5&quot;, FileFormat.WRITE);
    1131     * H5Datatype dtype = file.createDatatype(
    1132     *                             Datatype.CLASS_INTEGER,
    1133     *                             4,
    1134     *                             Datatype.NATIVE,
    1135     *                             Datatype.NATIVE);
    1136     * </pre>
    1137     *
    1138     * @param tclass
    1139     *            class of datatype, e.g. Datatype.CLASS_INTEGER
    1140     * @param tsize
    1141     *            size of the datatype in bytes, e.g. 4 for 32-bit integer.
    1142     * @param torder
    1143     *            order of the byte endian, e.g. Datatype.ORDER_LE.
    1144     * @param tsign
    1145     *            signed or unsigned of an integer, e.g. Datatype.SIGN_NONE.
    1146     * @return The new datatype object if successful; otherwise returns null.
    1147     * @throws Exception
    1148     *             The exceptions thrown vary depending on the implementing
    1149     *             class.
    1150     */
    1151    public abstract Datatype createDatatype(int tclass, int tsize, int torder, int tsign) throws Exception;
    1152
    1153    /**
    1154     * Creates a new datatype in memory.
    1155     *
    1156     * The following code creates an instance of H5Datatype in memory.
    1157     *
    1158     * <pre>
    1159     * H5File file = (H5File) h5file.createInstance(&quot;test_hdf5.h5&quot;, FileFormat.WRITE);
    1160     * H5Datatype dtype = file.createDatatype(
    1161     *                             Datatype.CLASS_INTEGER,
    1162     *                             4,
    1163     *                             Datatype.NATIVE,
    1164     *                             Datatype.NATIVE,
    1165     *                             basetype);
    1166     * </pre>
    1167     *
    1168     * @param tclass
    1169     *            class of datatype, e.g. Datatype.CLASS_INTEGER
    1170     * @param tsize
    1171     *            size of the datatype in bytes, e.g. 4 for 32-bit integer.
    1172     * @param torder
    1173     *            order of the byte endian, e.g. Datatype.ORDER_LE.
    1174     * @param tsign
    1175     *            signed or unsigned of an integer, e.g. Datatype.SIGN_NONE.
    1176     * @param tbase
    1177     *            the base datatype of the new datatype
    1178     * @return The new datatype object if successful; otherwise returns null.
    1179     * @throws Exception
    1180     *             The exceptions thrown vary depending on the implementing
    1181     *             class.
    1182     */
    1183    public Datatype createDatatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) throws Exception {
    1184        // Derived classes must override this function to use base type option
    1185        return createDatatype(tclass, tsize, torder, tsign);
    1186    }
    1187
    1188    // REVIEW DOCS for createDatatype(). Check and document exceptions.
    1189
    1190    /**
    1191     * Creates a new dataset in a file with/without chunking/compression.
    1192     *
    1193     * The following example creates a 2D integer dataset of size 100X50 at the root group in an HDF5
    1194     * file.
    1195     *
    1196     * <pre>
    1197     * String name = &quot;2D integer&quot;;
    1198     * Group pgroup = (Group) getRootObject();
    1199     * Datatype dtype = new H5Datatype(Datatype.CLASS_INTEGER, // class
    1200     *         4, // size in bytes
    1201     *         Datatype.ORDER_LE, // byte order
    1202     *         Datatype.SIGN_NONE); // unsigned
    1203     * long[] dims = { 100, 50 };
    1204     * long[] maxdims = dims;
    1205     * long[] chunks = null; // no
    1206     * // chunking
    1207     * int gzip = 0; // no compression
    1208     * Object data = null; // no initial data values
    1209     * Dataset d = (H5File) file.createScalarDS(name, pgroup, dtype, dims, maxdims, chunks, gzip, data);
    1210     * </pre>
    1211     *
    1212     * @param name
    1213     *            name of the new dataset, e.g. "2D integer"
    1214     * @param pgroup
    1215     *            parent group where the new dataset is created.
    1216     * @param type
    1217     *            datatype of the new dataset.
    1218     * @param dims
    1219     *            dimension sizes of the new dataset, e.g. long[] dims = {100, 50}.
    1220     * @param maxdims
    1221     *            maximum dimension sizes of the new dataset, null if maxdims is the same as dims.
    1222     * @param chunks
    1223     *            chunk sizes of the new dataset, null if no chunking.
    1224     * @param gzip
    1225     *            GZIP compression level (1 to 9), 0 or negative values if no compression.
    1226     * @param fillValue
    1227     *            default value.
    1228     * @param data
    1229     *            data written to the new dataset, null if no data is written to the new dataset.
    1230     *
    1231     * @return The new dataset if successful; otherwise returns null
    1232     * @throws Exception
    1233     *             The exceptions thrown vary depending on the implementing class.
    1234     */
    1235    public abstract Dataset createScalarDS(String name, Group pgroup, Datatype type,
    1236            long[] dims, long[] maxdims, long[] chunks,
    1237            int gzip, Object fillValue, Object data) throws Exception;
    1238
    1239    /**
    1240     * Creates a new dataset in a file with/without chunking/compression.
    1241     *
    1242     * @param name
    1243     *            name of the new dataset, e.g. "2D integer"
    1244     * @param pgroup
    1245     *            parent group where the new dataset is created.
    1246     * @param type
    1247     *            datatype of the new dataset.
    1248     * @param dims
    1249     *            dimension sizes of the new dataset, e.g. long[] dims = {100, 50}.
    1250     * @param maxdims
    1251     *            maximum dimension sizes of the new dataset, null if maxdims is the same as dims.
    1252     * @param chunks
    1253     *            chunk sizes of the new dataset, null if no chunking.
    1254     * @param gzip
    1255     *            GZIP compression level (1 to 9), 0 or negative values if no compression.
    1256     * @param data
    1257     *            data written to the new dataset, null if no data is written to the new dataset.
    1258     *
    1259     * @return The new dataset if successful; otherwise returns null
    1260     * @throws Exception
    1261     *             The exceptions thrown vary depending on the implementing class.
    1262     */
    1263    public Dataset createScalarDS(String name, Group pgroup, Datatype type,
    1264            long[] dims, long[] maxdims, long[] chunks,
    1265            int gzip, Object data) throws Exception {
    1266        return createScalarDS(name, pgroup, type, dims, maxdims, chunks, gzip, null, data);
    1267    }
    1268
    1269    // REVIEW DOCS for createScalarDS(). Check and document exceptions.
    1270
    1271    /**
    1272     * Creates a new compound dataset in a file with/without chunking and
    1273     * compression.
    1274     *
    1275     * The following example creates a compressed 2D compound dataset with size
    1276     * of 100X50 in a root group. The compound dataset has two members, x and y.
    1277     * Member x is an interger, member y is an 1-D float array of size 10.
    1278     *
    1279     * <pre>
    1280     * String name = "2D compound";
    1281     * Group pgroup = (Group) getRootObject();
    1282     * long[] dims = {100, 50};
    1283     * long[] chunks = {1, 50};
    1284     * int gzip = 9;
    1285     * String[] memberNames = {"x", "y"};
    1286     *
    1287     * Datatype[] memberDatatypes = {
    1288     *     new H5Datatype(Datatype.CLASS_INTEGER, Datatype.NATIVE,
    1289     *                    Datatype.NATIVE, Datatype.NATIVE)
    1290     *     new H5Datatype(Datatype.CLASS_FLOAT, Datatype.NATIVE,
    1291     *                    Datatype.NATIVE, Datatype.NATIVE));
    1292     *
    1293     * int[] memberSizes = {1, 10};
    1294     * Object data = null; // no initial data values
    1295     * Dataset d = (H5File)file.createCompoundDS(name, pgroup, dims, null,
    1296     *           chunks, gzip, memberNames, memberDatatypes, memberSizes, null);
    1297     * </pre>
    1298     *
    1299     * @param name
    1300     *            name of the new dataset
    1301     * @param pgroup
    1302     *            parent group where the new dataset is created.
    1303     * @param dims
    1304     *            dimension sizes of the new dataset.
    1305     * @param maxdims
    1306     *            maximum dimension sizes of the new dataset, null if maxdims is
    1307     *            the same as dims.
    1308     * @param chunks
    1309     *            chunk sizes of the new dataset, null if no chunking.
    1310     * @param gzip
    1311     *            GZIP compression level (1 to 9), 0 or negative values if no
    1312     *            compression.
    1313     * @param memberNames
    1314     *            names of the members.
    1315     * @param memberDatatypes
    1316     *            datatypes of the members.
    1317     * @param memberSizes
    1318     *            array sizes of the members.
    1319     * @param data
    1320     *            data written to the new dataset, null if no data is written to
    1321     *            the new dataset.
    1322     *
    1323     * @return new dataset object if successful; otherwise returns null
    1324     * @throws UnsupportedOperationException
    1325     *             If the implementing class does not support compound datasets.
    1326     * @throws Exception
    1327     *             The exceptions thrown vary depending on the implementing
    1328     *             class.
    1329     */
    1330    public Dataset createCompoundDS(String name, Group pgroup,
    1331            long[] dims, long[] maxdims, long[] chunks,
    1332            int gzip, String[] memberNames, Datatype[] memberDatatypes, int[] memberSizes, Object data) throws Exception {
    1333        // If the implementing subclass doesn't have this method then that
    1334        // format doesn't support Compound DataSets and we throw an
    1335        // exception.
    1336        throw new UnsupportedOperationException("Dataset FileFormat.createCompoundDS(...) is not implemented.");
    1337    }
    1338
    1339    /**
    1340     * Creates a new image in a file.
    1341     *
    1342     * The following example creates a 2D image of size 100X50 in a root group.
    1343     *
    1344     * <pre>
    1345     * String name = &quot;2D image&quot;;
    1346     * Group pgroup = (Group) getRootObject();
    1347     * Datatype dtype = new H5Datatype(Datatype.CLASS_INTEGER, 1, Datatype.NATIVE, Datatype.SIGN_NONE);
    1348     * long[] dims = {100, 50};
    1349     * long[] maxdims = dims;
    1350     * long[] chunks = null; // no chunking
    1351     * int gzip = 0; // no compression
    1352     * int ncomp = 3; // RGB true color image
    1353     * int interlace = ScalarDS.INTERLACE_PIXEL;
    1354     * Object data = null; // no initial data values
    1355     * Dataset d = (H5File) file.createScalarDS(name, pgroup, dtype, dims, maxdims, chunks, gzip, ncomp, interlace, data);
    1356     * </pre>
    1357     *
    1358     * @param name
    1359     *            name of the new image, "2D image".
    1360     * @param pgroup
    1361     *            parent group where the new image is created.
    1362     * @param type
    1363     *            datatype of the new image.
    1364     * @param dims
    1365     *            dimension sizes of the new dataset, e.g. long[] dims = {100,
    1366     *            50}.
    1367     * @param maxdims
    1368     *            maximum dimension sizes of the new dataset, null if maxdims is
    1369     *            the same as dims.
    1370     * @param chunks
    1371     *            chunk sizes of the new dataset, null if no chunking.
    1372     * @param gzip
    1373     *            GZIP compression level (1 to 9), 0 or negative values if no
    1374     *            compression.
    1375     * @param ncomp
    1376     *            number of components of the new image, e.g. int ncomp = 3; //
    1377     *            RGB true color image.
    1378     * @param interlace
    1379     *            interlace mode of the image. Valid values are
    1380     *            ScalarDS.INTERLACE_PIXEL, ScalarDS.INTERLACE_PLANEL and
    1381     *            ScalarDS.INTERLACE_LINE.
    1382     * @param data
    1383     *            data value of the image, null if no data.
    1384     *
    1385     * @return The new image object if successful; otherwise returns null
    1386     *
    1387     * @throws Exception
    1388     *             The exceptions thrown vary depending on the implementing
    1389     *             class.
    1390     */
    1391    public abstract Dataset createImage(String name, Group pgroup, Datatype type,
    1392            long[] dims, long[] maxdims, long[] chunks,
    1393            int gzip, int ncomp, int interlace, Object data) throws Exception;
    1394
    1395    // REVIEW DOCS for createImage(). Check and document exceptions.
    1396
    1397    /**
    1398     * Creates a new group with specified name in existing group.
    1399     *
    1400     * If the parent group is null, the new group will be created in the root
    1401     * group.
    1402     *
    1403     * @param name
    1404     *            The name of the new group.
    1405     * @param parentGroup
    1406     *            The parent group, or null.
    1407     *
    1408     * @return The new group if successful; otherwise returns null.
    1409     *
    1410     * @throws Exception
    1411     *             The exceptions thrown vary depending on the implementing
    1412     *             class.
    1413     */
    1414    public abstract Group createGroup(String name, Group parentGroup) throws Exception;
    1415
    1416    // REVIEW DOCS for createLink().
    1417    // Verify Implementing classes document these and also
    1418    // 'do the right thing' if fid is -1, currentObj is non-null, if
    1419    // object is null, or the root group then what? document & verify!
    1420
    1421    /**
    1422     * Creates a soft, hard or external link to an existing object in the open file.
    1423     *
    1424     * If parentGroup is null, the new link is created in the root group.
    1425     *
    1426     * @param parentGroup
    1427     *            The group where the link is created.
    1428     * @param name
    1429     *            The name of the link.
    1430     * @param currentObj
    1431     *            The existing object the new link will reference.
    1432     * @param type
    1433     *            The type of link to be created. It can be a hard link, a soft
    1434     *            link or an external link.
    1435     *
    1436     * @return The object pointed to by the new link if successful; otherwise
    1437     *         returns null.
    1438     *
    1439     * @throws Exception
    1440     *             The exceptions thrown vary depending on the implementing class.
    1441     */
    1442    public HObject createLink(Group parentGroup, String name, HObject currentObj, int type) throws Exception {
    1443        return createLink(parentGroup, name, currentObj);
    1444    }
    1445
    1446    /**
    1447     * Creates a soft or external link to an object in a file that does not exist
    1448     * at the time the link is created.
    1449     *
    1450     * @param parentGroup
    1451     *            The group where the link is created.
    1452     * @param name
    1453     *            The name of the link.
    1454     * @param currentObj
    1455     *            The name of the object the new link will reference. The object
    1456     *            doesn't have to exist.
    1457     * @param type
    1458     *            The type of link to be created.
    1459     *
    1460     * @return The H5Link object pointed to by the new link if successful;
    1461     *         otherwise returns null.
    1462     *
    1463     * @throws Exception
    1464     *             The exceptions thrown vary depending on the implementing class.
    1465     */
    1466    public HObject createLink(Group parentGroup, String name, String currentObj, int type) throws Exception {
    1467        return createLink(parentGroup, name, currentObj);
    1468    }
    1469
    1470    /**
    1471     * Copies the source object to a new destination.
    1472     *
    1473     * This method copies the source object to a destination group, and assigns
    1474     * the specified name to the new object.
    1475     *
    1476     * The copy may take place within a single file or across files. If the source
    1477     * object and destination group are in different files, the files must have
    1478     * the same file format (both HDF5 for example).
    1479     *
    1480     * The source object can be a group, a dataset, or a named datatype. This
    1481     * method copies the object along with all of its attributes and other
    1482     * properties. If the source object is a group, this method also copies all
    1483     * objects and sub-groups below the group.
    1484     *
    1485     * The following example shows how to use the copy method to create two
    1486     * copies of an existing HDF5 file structure in a new HDF5 file. One copy
    1487     * will be under /copy1 and the other under /copy2 in the new file.
    1488     *
    1489     * <pre>
    1490     * // Open the existing file with the source object.
    1491     * H5File existingFile = new H5File(&quot;existingFile.h5&quot;, FileFormat.READ);
    1492     * existingFile.open();
    1493     * // Our source object will be the root group.
    1494     * HObject srcObj = existingFile.get(&quot;/&quot;);
    1495     * // Create a new file.
    1496     * H5File newFile = new H5File(&quot;newFile.h5&quot;, FileFormat.CREATE);
    1497     * newFile.open();
    1498     * // Both copies in the new file will have the root group as their
    1499     * // destination group.
    1500     * Group dstGroup = (Group) newFile.get(&quot;/&quot;);
    1501     * // First copy goes to &quot;/copy1&quot; and second goes to &quot;/copy2&quot;.
    1502     * // Notice that we can use either H5File instance to perform the copy.
    1503     * HObject copy1 = existingFile.copy(srcObj, dstGroup, &quot;copy1&quot;);
    1504     * HObject copy2 = newFile.copy(srcObj, dstGroup, &quot;copy2&quot;);
    1505     * // Close both the files.
    1506     * file.close();
    1507     * newFile.close();
    1508     * </pre>
    1509     *
    1510     * @param srcObj
    1511     *            The object to copy.
    1512     * @param dstGroup
    1513     *            The destination group for the new object.
    1514     * @param dstName
    1515     *            The name of the new object. If dstName is null, the name of
    1516     *            srcObj will be used.
    1517     *
    1518     * @return The new object, or null if the copy fails.
    1519     *
    1520     * @throws Exception
    1521     *             are specific to the implementing class.
    1522     */
    1523    public abstract HObject copy(HObject srcObj, Group dstGroup, String dstName) throws Exception;
    1524
    1525    /**
    1526     * Deletes an object from a file.
    1527     *
    1528     * @param obj
    1529     *            The object to delete.
    1530     * @throws Exception
    1531     *             The exceptions thrown vary depending on the implementing class.
    1532     */
    1533    public abstract void delete(HObject obj) throws Exception;
    1534
    1535    // REVIEW DOCS for delete(). Check and document exceptions.
    1536
    1537    /**
    1538     * Attaches a given attribute to an object.
    1539     *
    1540     * If an HDF(4&amp;5) attribute exists in file, the method updates its value. If
    1541     * the attribute does not exist in file, it creates the attribute in file
    1542     * and attaches it to the object. It will fail to write a new attribute to
    1543     * the object where an attribute with the same name already exists. To
    1544     * update the value of an existing attribute in file, one needs to get the
    1545     * instance of the attribute by getMetadata(), change its values, and use
    1546     * writeAttribute() to write the value.
    1547     *
    1548     * @param obj
    1549     *            The object to which the attribute is attached to.
    1550     * @param attr
    1551     *            The atribute to attach.
    1552     * @param attrExisted
    1553     *            The indicator if the given attribute exists.
    1554     *
    1555     * @throws Exception
    1556     *             The exceptions thrown vary depending on the implementing class.
    1557     */
    1558    public abstract void writeAttribute(HObject obj, Attribute attr, boolean attrExisted) throws Exception;
    1559
    1560    // REVIEW DOCS for writeAttribute(). Check and document exceptions.
    1561
    1562    /***************************************************************************
    1563     * Deprecated methods.
    1564     **************************************************************************/
    1565
    1566    /**
    1567     * @deprecated As of 2.4, replaced by {@link #createFile(String, int)}
    1568     *
    1569     *             The replacement method has an additional parameter that
    1570     *             controls the behavior if the file already exists. Use
    1571     *             <code>FileFormat.FILE_CREATE_DELETE</code> as the second
    1572     *             argument in the replacement method to mimic the behavior
    1573     *             originally provided by this method.
    1574     *
    1575     * @param fileName
    1576     *            The filename; a pathname string.
    1577     *
    1578     * @return the created file object
    1579     *
    1580     * @throws Exception if file cannot be created
    1581     */
    1582    @Deprecated
    1583    public final FileFormat create(String fileName) throws Exception {
    1584        return createFile(fileName, FileFormat.FILE_CREATE_DELETE);
    1585    }
    1586
    1587    /**
    1588     * @deprecated As of 2.4, replaced by {@link #createInstance(String, int)}
    1589     *
    1590     *             The replacement method has identical functionality and a more
    1591     *             descriptive name. Since <i>open</i> is used elsewhere to
    1592     *             perform a different function this method has been deprecated.
    1593     *
    1594     * @param pathname
    1595     *            The pathname string.
    1596     * @param access
    1597     *            The file access properties
    1598     *
    1599     * @return the opened file object
    1600     *
    1601     * @throws Exception if the file cannot be opened
    1602     */
    1603    @Deprecated
    1604    public final FileFormat open(String pathname, int access) throws Exception {
    1605        return createInstance(pathname, access);
    1606    }
    1607
    1608    /**
    1609     * @deprecated As of 2.4, replaced by
    1610     *             {@link #createCompoundDS(String, Group, long[], long[], long[], int, String[], Datatype[], int[], Object)}
    1611     *
    1612     *             The replacement method has additional parameters:
    1613     *             <code>maxdims, chunks,</code> and <code>gzip</code>. To mimic
    1614     *             the behavior originally provided by this method, call the
    1615     *             replacement method with the following parameter list:
    1616     *             <code> ( name, pgroup, dims, null, null, -1,
    1617     * memberNames, memberDatatypes, memberSizes, data ); </code>
    1618     *
    1619     * @param name
    1620     *            The dataset name.
    1621     * @param pgroup
    1622     *            The dataset parent.
    1623     * @param dims
    1624     *            The dataset dimensions.
    1625     * @param memberNames
    1626     *            The dataset compound member names.
    1627     * @param memberDatatypes
    1628     *            The dataset compound member datatypes.
    1629     * @param memberSizes
    1630     *            The dataset compound member sizes.
    1631     * @param data
    1632     *            The dataset data.
    1633     *
    1634     * @return
    1635     *            The dataset created.
    1636     *
    1637     * @throws Exception if the dataset cannot be created
    1638     */
    1639    @Deprecated
    1640    public final Dataset createCompoundDS(String name, Group pgroup, long[] dims,
    1641            String[] memberNames, Datatype[] memberDatatypes, int[] memberSizes, Object data) throws Exception {
    1642        return createCompoundDS(name, pgroup, dims, null, null, -1, memberNames, memberDatatypes, memberSizes, data);
    1643    }
    1644
    1645    /**
    1646     * @deprecated As of 2.4, replaced by {@link #copy(HObject, Group, String)}
    1647     *
    1648     *             To mimic the behavior originally provided by this method,
    1649     *             call the replacement method with <code>null</code> as the 3rd parameter.
    1650     *
    1651     * @param srcObj
    1652     *             The object to be copied
    1653     * @param dstGroup
    1654     *             The group to contain the copied object
    1655     *
    1656     * @return the copied object
    1657     *
    1658     * @throws Exception if object can not be copied
    1659     */
    1660    @Deprecated
    1661    public final HObject copy(HObject srcObj, Group dstGroup) throws Exception {
    1662        return copy(srcObj, dstGroup, null);
    1663    }
    1664
    1665    /**
    1666     * @deprecated As of 2.4, replaced by {@link #get(String)}
    1667     *
    1668     *             This static method, which as been deprecated, causes two problems:
    1669     *             <ul>
    1670     *             <li>It can be very expensive if it is called many times or in
    1671     *             a loop because each call to the method creates an instance of a file.
    1672     *             <li>Since the method does not return the instance of the
    1673     *             file, the file cannot be closed directly and may be left open
    1674     *             (memory leak). The only way to close the file is through the
    1675     *             object returned by this method.
    1676     *             </ul>
    1677     *
    1678     * @param fullPath
    1679     *            The file path string.
    1680     *
    1681     * @return the object that has the given full path
    1682     *
    1683     * @throws Exception if the object can not be found
    1684     */
    1685    @Deprecated
    1686    public static final HObject getHObject(String fullPath) throws Exception {
    1687        if ((fullPath == null) || (fullPath.length() <= 0))
    1688            return null;
    1689
    1690        String filename = null, path = null;
    1691        int idx = fullPath.indexOf(FILE_OBJ_SEP);
    1692
    1693        if (idx > 0) {
    1694            filename = fullPath.substring(0, idx);
    1695            path = fullPath.substring(idx + FILE_OBJ_SEP.length());
    1696            if ((path == null) || (path.length() == 0))
    1697                path = "/";
    1698        }
    1699        else {
    1700            filename = fullPath;
    1701            path = "/";
    1702        }
    1703
    1704        return FileFormat.getHObject(filename, path);
    1705    };
    1706
    1707    /**
    1708     * @deprecated As of 2.4, replaced by {@link #get(String)}
    1709     *
    1710     *             This static method, which as been deprecated, causes two problems:
    1711     *             <ul>
    1712     *             <li>It can be very expensive if it is called many times or in
    1713     *             a loop because each call to the method creates an instance of
    1714     *             a file.
    1715     *             <li>Since the method does not return the instance of the
    1716     *             file, the file cannot be closed directly and may be left open
    1717     *             (memory leak). The only way to close the file is through the
    1718     *             object returned by this method, for example:
    1719     *             <pre>
    1720     * Dataset dset = H5File.getObject("hdf5_test.h5", "/images/iceburg");
    1721     * ...
    1722     * // close the file through dset
    1723     * dset.getFileFormat().close();
    1724     * </pre>
    1725     *
    1726     *             </li>
    1727     *             </ul>
    1728     *
    1729     * @param filename
    1730     *            The filename string.
    1731     * @param path
    1732     *            The path of the file
    1733     *
    1734     * @return the object that has the given filename and path returns null
    1735     *
    1736     * @throws Exception if the object can not be found
    1737     */
    1738    @Deprecated
    1739    public static final HObject getHObject(String filename, String path) throws Exception {
    1740        if ((filename == null) || (filename.length() <= 0))
    1741            throw new IllegalArgumentException("Invalid file name. " + filename);
    1742
    1743        if (!(new File(filename)).exists())
    1744            throw new IllegalArgumentException("File does not exists");
    1745
    1746        HObject obj = null;
    1747        FileFormat file = FileFormat.getInstance(filename);
    1748
    1749        if (file != null) {
    1750            obj = file.get(path);
    1751            if (obj == null)
    1752                file.close();
    1753        }
    1754
    1755        return obj;
    1756    }
    1757
    1758    /**
    1759     * Finds an object by its object ID
    1760     *
    1761     * @param file
    1762     *            the file containing the object
    1763     * @param oid
    1764     *            the oid to search for
    1765     *
    1766     * @return the object that has the given OID; otherwise returns null
    1767     */
    1768    public static final HObject findObject(FileFormat file, long[] oid) {
    1769        if ((file == null) || (oid == null)) {
    1770            log.debug("findObject(): file is null or oid is null");
    1771            return null;
    1772        }
    1773
    1774        HObject theObj = null;
    1775
    1776        HObject theRoot = file.getRootObject();
    1777        if (theRoot == null) {
    1778            log.debug("findObject(): rootObject is null");
    1779            return null;
    1780        }
    1781
    1782        Iterator<HObject> member_it = ((Group) theRoot).breadthFirstMemberList().iterator();
    1783        while (member_it.hasNext()) {
    1784            theObj = member_it.next();
    1785            if (theObj.equalsOID(oid))
    1786                break;
    1787        }
    1788
    1789        return theObj;
    1790    }
    1791
    1792    /**
    1793     * Finds an object by the full path of the object (path+name)
    1794     *
    1795     * @param file
    1796     *            the file containing the object
    1797     * @param path
    1798     *            the full path of the object to search for
    1799     *
    1800     * @return the object that has the given path; otherwise returns null
    1801     */
    1802    public static final HObject findObject(FileFormat file, String path) {
    1803        log.trace("findObject({}): start", path);
    1804
    1805        if ((file == null) || (path == null)) {
    1806            log.debug("findObject(): file is null or path is null");
    1807            return null;
    1808        }
    1809
    1810        if (!path.endsWith("/"))
    1811            path = path + "/";
    1812
    1813        HObject theRoot = file.getRootObject();
    1814
    1815        if (theRoot == null) {
    1816            log.debug("findObject(): rootObject is null");
    1817            return null;
    1818        }
    1819        else if (path.equals("/")) {
    1820            log.debug("findObject() path is rootObject");
    1821            return theRoot;
    1822        }
    1823
    1824        Iterator<HObject> member_it = ((Group) theRoot).breadthFirstMemberList().iterator();
    1825        HObject theObj = null;
    1826        while (member_it.hasNext()) {
    1827            theObj = member_it.next();
    1828            String fullPath = theObj.getFullName() + "/";
    1829
    1830            if (path.equals(fullPath) && theObj.getPath() != null)
    1831                break;
    1832            else
    1833                theObj = null;
    1834        }
    1835
    1836        return theObj;
    1837    }
    1838
    1839    // ////////////////////////////////////////////////////////////////////////////////////
    1840    // Added to support HDF5 1.8 features //
    1841    // ////////////////////////////////////////////////////////////////////////////////////
    1842
    1843    /**
    1844     * Opens file and returns a file identifier.
    1845     *
    1846     * @param indexList
    1847     *            The property list is the list of parameters, like index type
    1848     *            and the index order. The index type can be alphabetical or
    1849     *            creation. The index order can be increasing order or
    1850     *            decreasing order.
    1851     *
    1852     * @return File identifier if successful; otherwise -1.
    1853     *
    1854     * @throws Exception
    1855     *             The exceptions thrown vary depending on the implementing class.
    1856     */
    1857    public long open(int... indexList) throws Exception {
    1858        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:open.");
    1859    }
    1860
    1861    /**
    1862     * Creates a new group with specified name in existing group.
    1863     *
    1864     * If the parent group is null, the new group will be created in the root
    1865     * group.
    1866     *
    1867     * @param name
    1868     *            The name of a new group.
    1869     * @param pgroup
    1870     *            The parent group object.
    1871     * @param gplist
    1872     *            The group creation properties, in which the order of the
    1873     *            properties conforms the HDF5 library API, H5Gcreate(), i.e.
    1874     *            lcpl, gcpl and gapl, where
    1875     *            <ul>
    1876     *            <li>lcpl : Property list for link creation <li>gcpl : Property
    1877     *            list for group creation <li>gapl : Property list for group access
    1878     *            </ul>
    1879     *
    1880     * @return The new group if successful; otherwise returns null.
    1881     *
    1882     * @throws Exception
    1883     *             The exceptions thrown vary depending on the implementing class.
    1884     */
    1885    public Group createGroup(String name, Group pgroup, long... gplist) throws Exception {
    1886        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:createGroup.");
    1887    }
    1888
    1889    /***
    1890     * Creates the group creation property list identifier, gcpl. This
    1891     * identifier is used when creating Groups.
    1892     *
    1893     * @param creationorder
    1894     *            The order in which the objects in a group should be created.
    1895     *            It can be Tracked or Indexed.
    1896     * @param maxcompact
    1897     *            The maximum number of links to store in the group in a compact format.
    1898     * @param mindense
    1899     *            The minimum number of links to store in the indexed
    1900     *            format.Groups which are in indexed format and in which the
    1901     *            number of links falls below this threshold are automatically
    1902     *            converted to compact format.
    1903     *
    1904     * @return The gcpl identifier.
    1905     *
    1906     * @throws Exception
    1907     *             The exceptions thrown vary depending on the implementing class.
    1908     */
    1909    public long createGcpl(int creationorder, int maxcompact, int mindense) throws Exception {
    1910        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:createGcpl.");
    1911    }
    1912
    1913    /**
    1914     * Creates a link to an existing object in the open file.
    1915     *
    1916     * If linkGroup is null, the new link is created in the root group.
    1917     *
    1918     * @param linkGroup
    1919     *            The group where the link is created.
    1920     * @param name
    1921     *            The name of the link.
    1922     * @param currentObj
    1923     *            The existing object the new link will reference.
    1924     *
    1925     * @return The object pointed to by the new link if successful;
    1926     *         otherwise returns null.
    1927     *
    1928     * @throws Exception
    1929     *             The exceptions thrown vary depending on the implementing class.
    1930     */
    1931    public HObject createLink(Group linkGroup, String name, Object currentObj) throws Exception {
    1932        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:createLink.");
    1933    }
    1934
    1935    /**
    1936     * Export dataset.
    1937     *
    1938     * @param file_export_name
    1939     *            The file name to export data into.
    1940     * @param object
    1941     *            The HDF5 dataset object.
    1942     * @param binary_order
    1943     *            The data byte order
    1944     *
    1945     * @throws Exception
    1946     *             The exceptions thrown vary depending on the implementing class.
    1947     */
    1948    public void exportDataset(String file_export_name, Dataset object, int binary_order) throws Exception {
    1949        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:exportDataset.");
    1950    }
    1951
    1952    /**
    1953     * Renames an attribute.
    1954     *
    1955     * @param obj
    1956     *            The object whose attribute is to be renamed.
    1957     * @param oldAttrName
    1958     *            The current name of the attribute.
    1959     * @param newAttrName
    1960     *            The new name of the attribute.
    1961     *
    1962     * @throws Exception
    1963     *             The exceptions thrown vary depending on the implementing class.
    1964     */
    1965    public void renameAttribute(HObject obj, String oldAttrName, String newAttrName) throws Exception {
    1966        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:renameAttribute.");
    1967    }
    1968
    1969    /**
    1970     * Sets the bounds of new library versions.
    1971     *
    1972     * @param lowStr
    1973     *            The earliest version of the library.
    1974     * @param highStr
    1975     *            The latest version of the library.
    1976     *
    1977     * @throws Exception
    1978     *             The exceptions thrown vary depending on the implementing class.
    1979     */
    1980    public void setNewLibBounds(String lowStr, String highStr) throws Exception {
    1981        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:setNewLibBounds.");
    1982    }
    1983
    1984    /**
    1985     * Sets the bounds of library versions.
    1986     *
    1987     * @param lowStr
    1988     *            The earliest version of the library.
    1989     * @param highStr
    1990     *            The latest version of the library.
    1991     *
    1992     * @throws Exception
    1993     *             The exceptions thrown vary depending on the implementing class.
    1994     */
    1995    public void setLibBounds(String lowStr, String highStr) throws Exception {
    1996        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:setLibBounds.");
    1997    }
    1998
    1999    /**
    2000     * Gets the bounds of library versions
    2001     *
    2002     * @return The earliest and latest library versions in an int array.
    2003     *
    2004     * @throws Exception
    2005     *             The exceptions thrown vary depending on the implementing class.
    2006     */
    2007    public int[] getLibBounds() throws Exception {
    2008        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:getLibBounds.");
    2009    }
    2010
    2011    /**
    2012     * Initialize the bounds of library versions
    2013     *
    2014     * @throws Exception
    2015     *             The exceptions thrown vary depending on the implementing class.
    2016     */
    2017    public void initLibBounds() throws Exception {
    2018        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:initLibBounds.");
    2019    }
    2020
    2021    /**
    2022     * Gets the bounds of library versions as text.
    2023     *
    2024     * @return libversion The earliest and latest version of the library.
    2025     *
    2026     * @throws Exception
    2027     *             The exceptions thrown vary depending on the implementing class.
    2028     */
    2029    public String getLibBoundsDescription() throws Exception {
    2030        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:getLibBoundsDescription.");
    2031    }
    2032
    2033    /** @return the int value of the index type value.
    2034     *
    2035     * @param strtype
    2036     *            The name of the index type.
    2037     *
    2038     * @throws Exception
    2039     *             The exceptions thrown vary depending on the implementing class.
    2040     */
    2041    public static int getIndexTypeValue(String strtype) throws Exception {
    2042        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:getIndexTypeValue.");
    2043    }
    2044
    2045    /** @return the int value of the index type.
    2046     *
    2047     * @param strtype
    2048     *            The name of the index type.
    2049     *
    2050     * @throws Exception
    2051     *             The exceptions thrown vary depending on the implementing class.
    2052     */
    2053    public int getIndexType(String strtype) throws Exception {
    2054        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:getIndexType.");
    2055    }
    2056
    2057    /** set the int value of the index type.
    2058     *
    2059     * @param indexType
    2060     *            The value of the index type.
    2061     *
    2062     * @throws Exception
    2063     *             The exceptions thrown vary depending on the implementing class.
    2064     */
    2065    public void setIndexType(int indexType) throws Exception {
    2066        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:setIndexType.");
    2067    }
    2068
    2069    /** @return the int value of the index order value.
    2070     *
    2071     * @param strorder
    2072     *            The name of the index order.
    2073     *
    2074     * @throws Exception
    2075     *             The exceptions thrown vary depending on the implementing class.
    2076     */
    2077    public static int getIndexOrderValue(String strorder) throws Exception {
    2078        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:getIndexOrderValue.");
    2079    }
    2080
    2081    /** @return the int value of the index order.
    2082     *
    2083     * @param strorder
    2084     *            The name of the index order.
    2085     *
    2086     * @throws Exception
    2087     *             The exceptions thrown vary depending on the implementing class.
    2088     */
    2089    public int getIndexOrder(String strorder) throws Exception {
    2090        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:getIndexOrder.");
    2091    }
    2092
    2093    /** set the int value of the index order.
    2094     *
    2095     * @param indexOrder
    2096     *            The index order.
    2097     *
    2098     * @throws Exception
    2099     *             The exceptions thrown vary depending on the implementing class.
    2100     */
    2101    public void setIndexOrder(int indexOrder) throws Exception {
    2102        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:setIndexOrder.");
    2103    }
    2104}