001/*****************************************************************************
002 * Copyright by The HDF Group.                                               *
003 * Copyright by the Board of Trustees of the University of Illinois.         *
004 * All rights reserved.                                                      *
005 *                                                                           *
006 * This file is part of the HDF Java Products distribution.                  *
007 * The full copyright notice, including terms governing use, modification,   *
008 * and redistribution, is contained in the files COPYING and Copyright.html. *
009 * COPYING can be found at the root of the source code distribution tree.    *
010 * Or, see http://hdfgroup.org/products/hdf-java/doc/Copyright.html.         *
011 * If you do not have access to either file, you may request a copy from     *
012 * help@hdfgroup.org.                                                        *
013 ****************************************************************************/
014
015package hdf.view;
016
017import java.io.BufferedInputStream;
018import java.io.BufferedOutputStream;
019import java.io.File;
020import java.io.FileInputStream;
021import java.io.FileOutputStream;
022import java.io.RandomAccessFile;
023import java.util.Enumeration;
024import java.util.Hashtable;
025import java.util.StringTokenizer;
026
027import javax.swing.filechooser.FileFilter;
028
029/**
030 * A convenience implementation of FileFilter that filters out all files except
031 * for those type extensions that it knows about.
032 * 
033 * @author Peter X. Cao
034 * @version 2.4 9/6/2007
035 */
036public class DefaultFileFilter extends FileFilter {
037    private static FileFilter FILE_FILTER_HDF = null;
038    private static FileFilter FILE_FILTER_HDF4 = null;
039    private static FileFilter FILE_FILTER_HDF5 = null;
040    private static FileFilter FILE_FILTER_JPEG = null;
041    private static FileFilter FILE_FILTER_TIFF = null;
042    private static FileFilter FILE_FILTER_PNG = null;
043    private static FileFilter FILE_FILTER_GIF = null;
044    private static FileFilter FILE_FILTER_BMP = null;
045    private static FileFilter FILE_FILTER_IMG = null;
046    private static FileFilter FILE_FILTER_TEXT = null;
047    private static FileFilter FILE_FILTER_BINARY = null;
048
049    private static String fileExtension = ViewProperties.getFileExtension();
050
051    private Hashtable<String, DefaultFileFilter> filters = null;
052    private String description = null;
053    private String fullDescription = null;
054    private boolean useExtensionsInDescription = true;
055
056    /**
057     * Creates a file filter. If no filters are added, then all files are
058     * accepted.
059     * 
060     * @see #addExtension
061     */
062    public DefaultFileFilter() {
063        this.filters = new Hashtable<String, DefaultFileFilter>();
064    }
065
066    /**
067     * Creates a file filter that accepts files with the given extension.
068     * Example: new DefaultFileFilter("jpg");
069     * 
070     * @see #addExtension
071     */
072    public DefaultFileFilter(String extension) {
073        this(extension, null);
074    }
075
076    /**
077     * Creates a file filter that accepts the given file type. Example: new
078     * DefaultFileFilter("jpg", "JPEG Image Images");
079     * 
080     * Note that the "." before the extension is not needed. If provided, it
081     * will be ignored.
082     * 
083     * @see #addExtension
084     */
085    public DefaultFileFilter(String extension, String description) {
086        this();
087        if (extension != null) {
088            addExtension(extension);
089        }
090        if (description != null) {
091            setDescription(description);
092        }
093    }
094
095    /**
096     * Creates a file filter from the given string array. Example: new
097     * DefaultFileFilter(String {"gif", "jpg"});
098     * 
099     * Note that the "." before the extension is not needed adn will be ignored.
100     * 
101     * @see #addExtension
102     */
103    public DefaultFileFilter(String[] filters) {
104        this(filters, null);
105    }
106
107    /**
108     * Creates a file filter from the given string array and description.
109     * Example: new DefaultFileFilter(String {"gif", "jpg"},
110     * "Gif and JPG Images");
111     * 
112     * Note that the "." before the extension is not needed and will be ignored.
113     * 
114     * @see #addExtension
115     */
116    public DefaultFileFilter(String[] filters, String description) {
117        this();
118        for (int i = 0; i < filters.length; i++) {
119            // add filters one by one
120            addExtension(filters[i]);
121        }
122        if (description != null) {
123            setDescription(description);
124        }
125    }
126
127    /**
128     * Return true if this file should be shown in the directory pane, false if
129     * it shouldn't.
130     * 
131     * Files that begin with "." are ignored.
132     * 
133     * @see #getExtension
134     */
135    @Override
136        public boolean accept(File f) {
137        if (f != null) {
138            if (f.isDirectory()) {
139                return true;
140            }
141            String extension = getExtension(f);
142            if ((extension != null) && (filters.get(getExtension(f)) != null)) {
143                return true;
144            }
145        }
146
147        return false;
148    }
149
150    /**
151     * Return the extension portion of the file's name .
152     * 
153     * @see #getExtension
154     * @see FileFilter#accept
155     */
156    public String getExtension(File f) {
157        if (f != null) {
158            String filename = f.getName();
159            int i = filename.lastIndexOf('.');
160            if ((i > 0) && (i < filename.length() - 1)) {
161                return filename.substring(i + 1).toLowerCase();
162            }
163        }
164        return null;
165    }
166
167    /**
168     * Adds a filetype "dot" extension to filter against.
169     * 
170     * For example: the following code will create a filter that filters out all
171     * files except those that end in ".jpg" and ".tif":
172     * 
173     * DefaultFileFilter filter = new DefaultFileFilter();
174     * filter.addExtension("jpg"); filter.addExtension("tif"); or
175     * filter.addExtension("jpg, tif");
176     * 
177     * Note that the "." before the extension is not needed and will be ignored.
178     */
179    public void addExtension(String extension) {
180        if (filters == null) {
181            filters = new Hashtable<String, DefaultFileFilter>(5);
182        }
183
184        String ext = null;
185        StringTokenizer st = new StringTokenizer(extension, ",");
186        while (st.hasMoreElements()) {
187            ext = st.nextToken().trim();
188            filters.put(ext.toLowerCase(), this);
189        }
190        fullDescription = null;
191    }
192
193    /**
194     * Returns the human readable description of this filter. For example:
195     * "JPEG and GIF Image Files (*.jpg, *.gif)"
196     */
197    @Override
198        public String getDescription() {
199        if (fullDescription == null) {
200            if ((description == null) || isExtensionListInDescription()) {
201                fullDescription = description == null ? "(" : description
202                        + " (";
203                // build the description from the extension list
204                Enumeration<String> extensions = filters.keys();
205                if (extensions != null) {
206
207                    if (!extensions.hasMoreElements()) {
208                        fullDescription = null;
209                        return null;
210                    }
211
212                    fullDescription += "." + extensions.nextElement();
213                    while (extensions.hasMoreElements()) {
214                        fullDescription += ", "
215                                + extensions.nextElement();
216                    }
217                }
218                fullDescription += ")";
219            }
220            else {
221                fullDescription = description;
222            }
223        }
224        return fullDescription;
225    }
226
227    /**
228     * Sets the human readable description of this filter. For example:
229     * filter.setDescription("Gif and JPG Images");
230     */
231    public void setDescription(String description) {
232        this.description = description;
233        fullDescription = null;
234    }
235
236    /**
237     * Determines whether the extension list (.jpg, .gif, etc) should show up in
238     * the human readable description.
239     * 
240     * Only relevent if a description was provided in the constructor or using
241     * setDescription();
242     * 
243     */
244    public void setExtensionListInDescription(boolean b) {
245        useExtensionsInDescription = b;
246        fullDescription = null;
247    }
248
249    /**
250     * Returns whether the extension list (.jpg, .gif, etc) should show up in
251     * the human readable description.
252     * 
253     * Only relevent if a description was provided in the constructor or using
254     * setDescription();
255     */
256    public boolean isExtensionListInDescription() {
257        return useExtensionsInDescription;
258    }
259
260    /** Return a file filter for HDF4/5 file. */
261    public static FileFilter getFileFilter() {
262        boolean extensionNotChanged = (fileExtension
263                .equalsIgnoreCase(ViewProperties.getFileExtension()));
264
265        if ((FILE_FILTER_HDF != null) && extensionNotChanged) {
266            return FILE_FILTER_HDF;
267        }
268
269        // update extensions
270        fileExtension = ViewProperties.getFileExtension();
271
272        DefaultFileFilter filter = new DefaultFileFilter();
273        filter.setDescription("HDF & more");
274
275        filter.addExtension(fileExtension);
276
277        return (FILE_FILTER_HDF = filter);
278    }
279
280    /** Return a file filter for HDF4 file. */
281    public static FileFilter getFileFilterHDF4() {
282        if (FILE_FILTER_HDF4 != null) {
283            return FILE_FILTER_HDF4;
284        }
285
286        DefaultFileFilter filter = new DefaultFileFilter();
287        filter.addExtension("hdf");
288        filter.addExtension("h4");
289        filter.addExtension("hdf4");
290        filter.setDescription("HDF4 files");
291        FILE_FILTER_HDF4 = filter;
292
293        return FILE_FILTER_HDF4;
294    }
295
296    /** Return a file filter for HDF5 file. */
297    public static FileFilter getFileFilterHDF5() {
298        if (FILE_FILTER_HDF5 != null) {
299            return FILE_FILTER_HDF5;
300        }
301
302        DefaultFileFilter filter = new DefaultFileFilter();
303        filter.addExtension("h5");
304        filter.addExtension("hdf5");
305        filter.setDescription("HDF5 files");
306        FILE_FILTER_HDF5 = filter;
307
308        return FILE_FILTER_HDF5;
309    }
310
311    /** Return a file filter for JPEG image files. */
312    public static FileFilter getFileFilterJPEG() {
313        if (FILE_FILTER_JPEG != null) {
314            return FILE_FILTER_JPEG;
315        }
316
317        DefaultFileFilter filter = new DefaultFileFilter();
318        filter.addExtension("jpg");
319        filter.addExtension("jpeg");
320        filter.addExtension("jpe");
321        filter.addExtension("jif");
322        filter.addExtension("jfif");
323        filter.addExtension("jfi");
324        filter.setDescription("JPEG images");
325        FILE_FILTER_JPEG = filter;
326
327        return FILE_FILTER_JPEG;
328    }
329
330    /** Return a file filter for TIFF image files. */
331    public static FileFilter getFileFilterTIFF() {
332        if (FILE_FILTER_TIFF != null) {
333            return FILE_FILTER_TIFF;
334        }
335
336        DefaultFileFilter filter = new DefaultFileFilter();
337        filter.addExtension("tif");
338        filter.addExtension("tiff");
339        filter.setDescription("TIFF images");
340        FILE_FILTER_TIFF = filter;
341
342        return FILE_FILTER_TIFF;
343    }
344
345    /** Return a file filter for PNG image files. */
346    public static FileFilter getFileFilterPNG() {
347        if (FILE_FILTER_PNG != null) {
348            return FILE_FILTER_PNG;
349        }
350
351        DefaultFileFilter filter = new DefaultFileFilter();
352        filter.addExtension("png");
353        filter.setDescription("PNG images");
354        FILE_FILTER_PNG = filter;
355
356        return FILE_FILTER_PNG;
357    }
358
359    /** Return a file filter for BMP image files. */
360    public static FileFilter getFileFilterBMP() {
361        if (FILE_FILTER_BMP != null) {
362            return FILE_FILTER_BMP;
363        }
364
365        DefaultFileFilter filter = new DefaultFileFilter();
366        filter.addExtension("bmp");
367        filter.addExtension("dib");
368        filter.setDescription("BMP images");
369        FILE_FILTER_BMP = filter;
370
371        return FILE_FILTER_BMP;
372    }
373
374    /** Return a file filter for GIF image files. */
375    public static FileFilter getFileFilterGIF() {
376        if (FILE_FILTER_GIF != null) {
377            return FILE_FILTER_GIF;
378        }
379
380        DefaultFileFilter filter = new DefaultFileFilter();
381        filter.addExtension("gif");
382        filter.setDescription("GIF images");
383        FILE_FILTER_GIF = filter;
384
385        return FILE_FILTER_GIF;
386    }
387
388    /** Return a file filter for GIF, JPEG, BMP, or PNG image files. */
389    public static FileFilter getImageFileFilter() {
390        if (FILE_FILTER_IMG != null) {
391            return FILE_FILTER_IMG;
392        }
393
394        DefaultFileFilter filter = new DefaultFileFilter();
395        filter.addExtension("jpg");
396        filter.addExtension("jpeg");
397        filter.addExtension("jpe");
398        filter.addExtension("jif");
399        filter.addExtension("jfif");
400        filter.addExtension("jfi");
401        filter.addExtension("png");
402        filter.addExtension("gif");
403        filter.addExtension("bmp");
404        filter.addExtension("dib");
405        filter.setDescription("GIF, JPEG, BMP, or PNG images");
406        FILE_FILTER_IMG = filter;
407
408        return FILE_FILTER_IMG;
409    }
410
411    /** Return a file filter for text file. */
412    public static FileFilter getFileFilterText() {
413        if (FILE_FILTER_TEXT != null) {
414            return FILE_FILTER_TEXT;
415        }
416
417        DefaultFileFilter filter = new DefaultFileFilter();
418        filter.addExtension("txt");
419        filter.addExtension("text");
420        filter.setDescription("Text");
421        FILE_FILTER_TEXT = filter;
422
423        return FILE_FILTER_TEXT;
424    }
425    
426    /** Return a file filter for binary file. */
427    public static FileFilter getFileFilterBinary() {
428        if (FILE_FILTER_BINARY != null) {
429            return FILE_FILTER_BINARY;
430        }
431
432        DefaultFileFilter filter = new DefaultFileFilter();
433        filter.addExtension("bin");
434        filter.setDescription("Binary");
435        FILE_FILTER_BINARY = filter;
436
437        return FILE_FILTER_BINARY;
438    }
439
440    /**
441     * look at the first 4 bytes of the file to see if it is an HDF4 file.
442     * byte[0]=14, byte[1]=3, byte[2]=19, byte[3]=1 or if it is a netCDF file
443     * byte[0]=67, byte[1]=68, byte[2]=70, byte[3]=1 or
444     */
445    public static boolean isHDF4(String filename) {
446        boolean ish4 = false;
447        RandomAccessFile raf = null;
448
449        try {
450            raf = new RandomAccessFile(filename, "r");
451        }
452        catch (Exception ex) {
453            raf = null;
454        }
455
456        if (raf == null) {
457            return false;
458        }
459
460        byte[] header = new byte[4];
461        try {
462            raf.read(header);
463        }
464        catch (Exception ex) {
465            header = null;
466        }
467
468        if (header != null) {
469            if (
470            // HDF4
471            ((header[0] == 14) && (header[1] == 3) && (header[2] == 19) && (header[3] == 1))
472            /*
473             * // netCDF || (header[0]==67 && header[1]==68 && header[2]==70 &&
474             * header[3]==1)
475             */
476            ) {
477                ish4 = true;
478            }
479            else {
480                ish4 = false;
481            }
482        }
483
484        try {
485            raf.close();
486        }
487        catch (Exception ex) {
488        }
489
490        return ish4;
491    }
492
493    /**
494     * look at the first 8 bytes of the file to see if it is an HDF5 file.
495     * byte[0]=-199 which is 137 in unsigned byte, byte[1]=72, byte[2]=68,
496     * byte[3]=70, byte[4]=13, byte[5]=10, byte[6]=26, byte[7]=10
497     */
498    public static boolean isHDF5(String filename) {
499        boolean ish5 = false;
500        RandomAccessFile raf = null;
501
502        try {
503            raf = new RandomAccessFile(filename, "r");
504        }
505        catch (Exception ex) {
506            raf = null;
507        }
508
509        if (raf == null) {
510            return false;
511        }
512
513        byte[] header = new byte[8];
514        long fileSize = 0;
515        try {
516            fileSize = raf.length();
517        }
518        catch (Exception ex) {
519        }
520
521        // The super block is located by searching for the HDF5 file signature
522        // at byte offset 0, byte offset 512 and at successive locations in the
523        // file, each a multiple of two of the previous location, i.e. 0, 512,
524        // 1024, 2048, etc
525        long offset = 0;
526        while (!ish5 && (offset < fileSize)) {
527            try {
528                raf.seek(offset);
529                raf.read(header);
530            }
531            catch (Exception ex) {
532                header = null;
533            }
534
535            if ((header[0] == -119) && (header[1] == 72) && (header[2] == 68)
536                    && (header[3] == 70) && (header[4] == 13)
537                    && (header[5] == 10) && (header[6] == 26)
538                    && (header[7] == 10)) {
539                ish5 = true;
540            }
541            else {
542                ish5 = false;
543                if (offset == 0) {
544                    offset = 512;
545                }
546                else {
547                    offset *= 2;
548                }
549            }
550        }
551
552        try {
553            raf.close();
554        }
555        catch (Exception ex) {
556        }
557
558        return ish5;
559    }
560
561    /**
562     * look at the first 4 bytes of the file to see if it is a netCDF file
563     * byte[0]=67, byte[1]=68, byte[2]=70, byte[3]=1 or
564     */
565    public static boolean isNetcdf(String filename) {
566        boolean isnc = false;
567        RandomAccessFile raf = null;
568
569        try {
570            raf = new RandomAccessFile(filename, "r");
571        }
572        catch (Exception ex) {
573            raf = null;
574        }
575
576        if (raf == null) {
577            return false;
578        }
579
580        byte[] header = new byte[4];
581        try {
582            raf.read(header);
583        }
584        catch (Exception ex) {
585            header = null;
586        }
587
588        if (header != null) {
589            if (
590            // netCDF
591            (header[0] == 67) && (header[1] == 68) && (header[2] == 70)
592                    && (header[3] == 1)) {
593                isnc = true;
594            }
595            else {
596                isnc = false;
597            }
598        }
599
600        try {
601            raf.close();
602        }
603        catch (Exception ex) {
604        }
605
606        return isnc;
607    }
608
609    /**
610     * Read HDF5 user block data into byte array.
611     * 
612     * @return a byte array of user block, or null if there is user data.
613     */
614    public static byte[] getHDF5UserBlock(String filename) {
615        byte[] userBlock = null;
616        RandomAccessFile raf = null;
617
618        try {
619            raf = new RandomAccessFile(filename, "r");
620        }
621        catch (Exception ex) {
622            try {
623                raf.close();
624            }
625            catch (Throwable err) {
626                ;
627            }
628            raf = null;
629        }
630
631        if (raf == null) {
632            return null;
633        }
634
635        byte[] header = new byte[8];
636        long fileSize = 0;
637        try {
638            fileSize = raf.length();
639        }
640        catch (Exception ex) {
641            fileSize = 0;
642        }
643        if (fileSize <= 0) {
644            try {
645                raf.close();
646            }
647            catch (Throwable err) {
648                ;
649            }
650            return null;
651        }
652
653        // The super block is located by searching for the HDF5 file signature
654        // at byte offset 0, byte offset 512 and at successive locations in the
655        // file, each a multiple of two of the previous location, i.e. 0, 512,
656        // 1024, 2048, etc
657        long offset = 0;
658        boolean ish5 = false;
659        while (offset < fileSize) {
660            try {
661                raf.seek(offset);
662                raf.read(header);
663            }
664            catch (Exception ex) {
665                header = null;
666            }
667
668            if ((header[0] == -119) && (header[1] == 72) && (header[2] == 68)
669                    && (header[3] == 70) && (header[4] == 13)
670                    && (header[5] == 10) && (header[6] == 26)
671                    && (header[7] == 10)) {
672                ish5 = true;
673                break; // find the end of user block
674            }
675            else {
676                ish5 = false;
677                if (offset == 0) {
678                    offset = 512;
679                }
680                else {
681                    offset *= 2;
682                }
683            }
684        }
685
686        if (!ish5 || (offset == 0)) {
687            try {
688                raf.close();
689            }
690            catch (Throwable err) {
691                ;
692            }
693            return null;
694        }
695
696        int blockSize = (int) offset;
697        userBlock = new byte[blockSize];
698        try {
699            raf.seek(0);
700            raf.read(userBlock, 0, blockSize);
701        }
702        catch (Exception ex) {
703            userBlock = null;
704        }
705
706        try {
707            raf.close();
708        }
709        catch (Exception ex) {
710        }
711
712        return userBlock;
713    }
714
715    /**
716     * Write HDF5 user block data into byte array.
717     * 
718     * @return a byte array of user block, or null if there is user data.
719     */
720    public static boolean setHDF5UserBlock(String fin, String fout, byte[] buf) {
721        boolean ish5 = false;
722
723        if ((buf == null) || (buf.length <= 0)) {
724            return false;
725        }
726
727        File tmpFile = new File(fin);
728        if (!tmpFile.exists()) {
729            return false;
730        }
731
732        // find the end of user block for the input file;
733        RandomAccessFile raf = null;
734        try {
735            raf = new RandomAccessFile(fin, "r");
736        }
737        catch (Exception ex) {
738            raf = null;
739        }
740
741        if (raf == null) {
742            return false;
743        }
744
745        byte[] header = new byte[8];
746        long fileSize = 0;
747        try {
748            fileSize = raf.length();
749        }
750        catch (Exception ex) {
751            fileSize = 0;
752        }
753        try {
754            fileSize = raf.length();
755        }
756        catch (Exception ex) {
757            fileSize = 0;
758        }
759        if (fileSize <= 0) {
760            try {
761                raf.close();
762            }
763            catch (Throwable err) {
764                ;
765            }
766            return false;
767        }
768
769        // The super block is located by searching for the HDF5 file signature
770        // at byte offset 0, byte offset 512 and at successive locations in the
771        // file, each a multiple of two of the previous location, i.e. 0, 512,
772        // 1024, 2048, etc
773        long offset = 0;
774        while (offset < fileSize) {
775            try {
776                raf.seek(offset);
777                raf.read(header);
778            }
779            catch (Exception ex) {
780                header = null;
781            }
782
783            if ((header[0] == -119) && (header[1] == 72) && (header[2] == 68)
784                    && (header[3] == 70) && (header[4] == 13)
785                    && (header[5] == 10) && (header[6] == 26)
786                    && (header[7] == 10)) {
787                ish5 = true;
788                break;
789            }
790            else {
791                ish5 = false;
792                if (offset == 0) {
793                    offset = 512;
794                }
795                else {
796                    offset *= 2;
797                }
798            }
799        }
800        try {
801            raf.close();
802        }
803        catch (Throwable err) {
804            ;
805        }
806
807        if (!ish5) {
808            return false;
809        }
810
811        int length = 0;
812        int bsize = 1024;
813        byte[] buffer;
814        BufferedInputStream bi = null;
815        BufferedOutputStream bo = null;
816
817        try {
818            bi = new BufferedInputStream(new FileInputStream(fin));
819        }
820        catch (Exception ex) {
821            try {
822                bi.close();
823            }
824            catch (Exception ex2) {
825            }
826            return false;
827        }
828
829        try {
830            bo = new BufferedOutputStream(new FileOutputStream(fout));
831        }
832        catch (Exception ex) {
833            try {
834                bo.close();
835            }
836            catch (Exception ex2) {
837            }
838            try {
839                bi.close();
840            }
841            catch (Exception ex2) {
842            }
843            return false;
844        }
845
846        // skip the header of original file
847        try {
848            bi.skip(offset);
849        }
850        catch (Exception ex) {
851        }
852
853        // write the header into the new file
854        try {
855            bo.write(buf, 0, buf.length);
856        }
857        catch (Exception ex) {
858        }
859
860        // The super block space is allocated by offset 0, 512, 1024, 2048, etc
861        offset = 512;
862        while (offset < buf.length) {
863            offset *= 2;
864        }
865        int padSize = (int) (offset - buf.length);
866        if (padSize > 0) {
867            byte[] padBuf = new byte[padSize];
868            try {
869                bo.write(padBuf, 0, padSize);
870            }
871            catch (Exception ex) {
872            }
873        }
874
875        // copy the hdf5 file content from input file to the output file
876        buffer = new byte[bsize];
877        try {
878            length = bi.read(buffer, 0, bsize);
879        }
880        catch (Exception ex) {
881            length = 0;
882        }
883        while (length > 0) {
884            try {
885                bo.write(buffer, 0, length);
886                length = bi.read(buffer, 0, bsize);
887            }
888            catch (Exception ex) {
889                length = 0;
890            }
891        }
892
893        try {
894            bo.flush();
895        }
896        catch (Exception ex) {
897        }
898        try {
899            bi.close();
900        }
901        catch (Exception ex) {
902        }
903        try {
904            bo.close();
905        }
906        catch (Exception ex) {
907        }
908        return true;
909    }
910}