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