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