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