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