001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     * 
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.io.filefilter;
018    
019    import java.io.File;
020    import java.io.FileFilter;
021    import java.io.FilenameFilter;
022    import java.util.ArrayList;
023    import java.util.Arrays;
024    import java.util.Collection;
025    import java.util.Date;
026    import java.util.HashSet;
027    import java.util.List;
028    import java.util.Set;
029    
030    import org.apache.commons.io.IOCase;
031    
032    /**
033     * Useful utilities for working with file filters. It provides access to all
034     * file filter implementations in this package so you don't have to import
035     * every class you use.
036     * 
037     * @since Commons IO 1.0
038     * @version $Id: FileFilterUtils.java 1005099 2010-10-06 16:13:01Z niallp $
039     * 
040     * @author Stephen Colebourne
041     * @author Jeremias Maerki
042     * @author Masato Tezuka
043     * @author Rahul Akolkar
044     */
045    public class FileFilterUtils {
046        
047        /**
048         * FileFilterUtils is not normally instantiated.
049         */
050        public FileFilterUtils() {
051        }
052    
053        //-----------------------------------------------------------------------
054    
055        /**
056         * <p>
057         * Applies an {@link IOFileFilter} to the provided {@link File} 
058         * objects. The resulting array is a subset of the original file list that 
059         * matches the provided filter.
060         * </p>
061         * 
062         * <p>
063         * The {@link Set} returned by this method is not guaranteed to be thread safe.
064         * </p>
065         * 
066         * <pre>
067         * Set&lt;File&gt; allFiles = ...
068         * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
069         *     FileFilterUtils.suffixFileFilter(".java"));
070         * </pre>
071         * @param filter the filter to apply to the set of files.
072         * @param files the array of files to apply the filter to.
073         * 
074         * @return a subset of <code>files</code> that is accepted by the 
075         *         file filter.
076         * @throws IllegalArgumentException if the filter is <code>null</code> 
077         *         or <code>files</code> contains a <code>null</code> value. 
078         * 
079         * @since Commons IO 2.0
080         */
081        public static File[] filter(IOFileFilter filter, File... files) {
082            if (filter == null) {
083                throw new IllegalArgumentException("file filter is null");
084            }
085            if (files == null) {
086                return new File[0];
087            }
088            List<File> acceptedFiles = new ArrayList<File>();
089            for (File file : files) {
090                if (file == null) {
091                    throw new IllegalArgumentException("file array contains null");
092                }
093                if (filter.accept(file)) {
094                    acceptedFiles.add(file);
095                }
096            }
097            return acceptedFiles.toArray(new File[acceptedFiles.size()]);
098        }
099    
100        /**
101         * <p>
102         * Applies an {@link IOFileFilter} to the provided {@link File} 
103         * objects. The resulting array is a subset of the original file list that 
104         * matches the provided filter.
105         * </p>
106         * 
107         * <p>
108         * The {@link Set} returned by this method is not guaranteed to be thread safe.
109         * </p>
110         * 
111         * <pre>
112         * Set&lt;File&gt; allFiles = ...
113         * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
114         *     FileFilterUtils.suffixFileFilter(".java"));
115         * </pre>
116         * @param filter the filter to apply to the set of files.
117         * @param files the array of files to apply the filter to.
118         * 
119         * @return a subset of <code>files</code> that is accepted by the 
120         *         file filter.
121         * @throws IllegalArgumentException if the filter is <code>null</code> 
122         *         or <code>files</code> contains a <code>null</code> value. 
123         * 
124         * @since Commons IO 2.0
125         */
126        public static File[] filter(IOFileFilter filter, Iterable<File> files) {
127            List<File> acceptedFiles = filterList(filter, files);
128            return acceptedFiles.toArray(new File[acceptedFiles.size()]);
129        }
130    
131        /**
132         * <p>
133         * Applies an {@link IOFileFilter} to the provided {@link File} 
134         * objects. The resulting list is a subset of the original files that 
135         * matches the provided filter.
136         * </p>
137         * 
138         * <p>
139         * The {@link List} returned by this method is not guaranteed to be thread safe.
140         * </p>
141         * 
142         * <pre>
143         * List&lt;File&gt; filesAndDirectories = ...
144         * List&lt;File&gt; directories = FileFilterUtils.filterList(filesAndDirectories,
145         *     FileFilterUtils.directoryFileFilter());
146         * </pre>
147         * @param filter the filter to apply to each files in the list.
148         * @param files the collection of files to apply the filter to.
149         * 
150         * @return a subset of <code>files</code> that is accepted by the 
151         *         file filter.
152         * @throws IllegalArgumentException if the filter is <code>null</code> 
153         *         or <code>files</code> contains a <code>null</code> value. 
154         * @since Commons IO 2.0
155         */
156        public static List<File> filterList(IOFileFilter filter, Iterable<File> files) {
157            return filter(filter, files, new ArrayList<File>());
158        }
159    
160        /**
161         * <p>
162         * Applies an {@link IOFileFilter} to the provided {@link File} 
163         * objects. The resulting list is a subset of the original files that 
164         * matches the provided filter.
165         * </p>
166         * 
167         * <p>
168         * The {@link List} returned by this method is not guaranteed to be thread safe.
169         * </p>
170         * 
171         * <pre>
172         * List&lt;File&gt; filesAndDirectories = ...
173         * List&lt;File&gt; directories = FileFilterUtils.filterList(filesAndDirectories,
174         *     FileFilterUtils.directoryFileFilter());
175         * </pre>
176         * @param filter the filter to apply to each files in the list.
177         * @param files the collection of files to apply the filter to.
178         * 
179         * @return a subset of <code>files</code> that is accepted by the 
180         *         file filter.
181         * @throws IllegalArgumentException if the filter is <code>null</code> 
182         *         or <code>files</code> contains a <code>null</code> value. 
183         * @since Commons IO 2.0
184         */
185        public static List<File> filterList(IOFileFilter filter, File... files) {
186            File[] acceptedFiles = filter(filter, files);
187            return Arrays.asList(acceptedFiles);
188        }
189    
190        /**
191         * <p>
192         * Applies an {@link IOFileFilter} to the provided {@link File} 
193         * objects. The resulting set is a subset of the original file list that 
194         * matches the provided filter.
195         * </p>
196         * 
197         * <p>
198         * The {@link Set} returned by this method is not guaranteed to be thread safe.
199         * </p>
200         * 
201         * <pre>
202         * Set&lt;File&gt; allFiles = ...
203         * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
204         *     FileFilterUtils.suffixFileFilter(".java"));
205         * </pre>
206         * @param filter the filter to apply to the set of files.
207         * @param files the collection of files to apply the filter to.
208         * 
209         * @return a subset of <code>files</code> that is accepted by the 
210         *         file filter.
211         * @throws IllegalArgumentException if the filter is <code>null</code> 
212         *         or <code>files</code> contains a <code>null</code> value. 
213         * 
214         * @since Commons IO 2.0
215         */
216        public static Set<File> filterSet(IOFileFilter filter, File... files) {
217            File[] acceptedFiles = filter(filter, files);
218            return new HashSet<File>(Arrays.asList(acceptedFiles));
219        }
220    
221        /**
222         * <p>
223         * Applies an {@link IOFileFilter} to the provided {@link File} 
224         * objects. The resulting set is a subset of the original file list that 
225         * matches the provided filter.
226         * </p>
227         * 
228         * <p>
229         * The {@link Set} returned by this method is not guaranteed to be thread safe.
230         * </p>
231         * 
232         * <pre>
233         * Set&lt;File&gt; allFiles = ...
234         * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
235         *     FileFilterUtils.suffixFileFilter(".java"));
236         * </pre>
237         * @param filter the filter to apply to the set of files.
238         * @param files the collection of files to apply the filter to.
239         * 
240         * @return a subset of <code>files</code> that is accepted by the 
241         *         file filter.
242         * @throws IllegalArgumentException if the filter is <code>null</code> 
243         *         or <code>files</code> contains a <code>null</code> value. 
244         * 
245         * @since Commons IO 2.0
246         */
247        public static Set<File> filterSet(IOFileFilter filter, Iterable<File> files) {
248            return filter(filter, files, new HashSet<File>());
249        }
250    
251        /**
252         * <p>
253         * Applies an {@link IOFileFilter} to the provided {@link File} 
254         * objects and appends the accepted files to the other supplied collection. 
255         * </p>
256         * 
257         * <pre>
258         * List&lt;File&gt; files = ...
259         * List&lt;File&gt; directories = FileFilterUtils.filterList(files,
260         *     FileFilterUtils.sizeFileFilter(FileUtils.FIFTY_MB), 
261         *         new ArrayList&lt;File&gt;());
262         * </pre>
263         * @param filter the filter to apply to the collection of files.
264         * @param files the collection of files to apply the filter to.
265         * @param acceptedFiles the list of files to add accepted files to.
266         * 
267         * @param <T> the type of the file collection.
268         * @return a subset of <code>files</code> that is accepted by the 
269         *         file filter.
270         * @throws IllegalArgumentException if the filter is <code>null</code> 
271         *         or <code>files</code> contains a <code>null</code> value. 
272         */
273        private static <T extends Collection<File>> T filter(IOFileFilter filter,
274                Iterable<File> files, T acceptedFiles) {
275            if (filter == null) {
276                throw new IllegalArgumentException("file filter is null");
277            }
278            if (files != null) {
279                for (File file : files) {
280                    if (file == null) {
281                        throw new IllegalArgumentException("file collection contains null");
282                    }
283                    if (filter.accept(file)) {
284                        acceptedFiles.add(file);
285                    }
286                }
287            }
288            return acceptedFiles;
289        }
290    
291        /**
292         * Returns a filter that returns true if the filename starts with the specified text.
293         * 
294         * @param prefix  the filename prefix
295         * @return a prefix checking filter
296         * @see PrefixFileFilter
297         */
298        public static IOFileFilter prefixFileFilter(String prefix) {
299            return new PrefixFileFilter(prefix);
300        }
301    
302        /**
303         * Returns a filter that returns true if the filename starts with the specified text.
304         * 
305         * @param prefix  the filename prefix
306         * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
307         * @return a prefix checking filter
308         * @see PrefixFileFilter
309         * @since Commons IO 2.0
310         */
311        public static IOFileFilter prefixFileFilter(String prefix, IOCase caseSensitivity) {
312            return new PrefixFileFilter(prefix, caseSensitivity);
313        }
314    
315        /**
316         * Returns a filter that returns true if the filename ends with the specified text.
317         * 
318         * @param suffix  the filename suffix
319         * @return a suffix checking filter
320         * @see SuffixFileFilter
321         */
322        public static IOFileFilter suffixFileFilter(String suffix) {
323            return new SuffixFileFilter(suffix);
324        }
325    
326        /**
327         * Returns a filter that returns true if the filename ends with the specified text.
328         * 
329         * @param suffix  the filename suffix
330         * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
331         * @return a suffix checking filter
332         * @see SuffixFileFilter
333         * @since Commons IO 2.0
334         */
335        public static IOFileFilter suffixFileFilter(String suffix, IOCase caseSensitivity) {
336            return new SuffixFileFilter(suffix, caseSensitivity);
337        }
338    
339        /**
340         * Returns a filter that returns true if the filename matches the specified text.
341         * 
342         * @param name  the filename
343         * @return a name checking filter
344         * @see NameFileFilter
345         */
346        public static IOFileFilter nameFileFilter(String name) {
347            return new NameFileFilter(name);
348        }
349    
350        /**
351         * Returns a filter that returns true if the filename matches the specified text.
352         * 
353         * @param name  the filename
354         * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
355         * @return a name checking filter
356         * @see NameFileFilter
357         * @since Commons IO 2.0
358         */
359        public static IOFileFilter nameFileFilter(String name, IOCase caseSensitivity) {
360            return new NameFileFilter(name, caseSensitivity);
361        }
362    
363        /**
364         * Returns a filter that checks if the file is a directory.
365         * 
366         * @return file filter that accepts only directories and not files
367         * @see DirectoryFileFilter#DIRECTORY
368         */
369        public static IOFileFilter directoryFileFilter() {
370            return DirectoryFileFilter.DIRECTORY;
371        }
372    
373        /**
374         * Returns a filter that checks if the file is a file (and not a directory).
375         * 
376         * @return file filter that accepts only files and not directories
377         * @see FileFileFilter#FILE
378         */
379        public static IOFileFilter fileFileFilter() {
380            return FileFileFilter.FILE;
381        }
382    
383        //-----------------------------------------------------------------------
384        /**
385         * Returns a filter that ANDs the two specified filters.
386         * 
387         * @param filter1  the first filter
388         * @param filter2  the second filter
389         * @return a filter that ANDs the two specified filters
390         * @see #and(IOFileFilter...)
391         * @see AndFileFilter
392         * @deprecated use {@link #and(IOFileFilter...)}
393         */
394        @Deprecated
395        public static IOFileFilter andFileFilter(IOFileFilter filter1, IOFileFilter filter2) {
396            return new AndFileFilter(filter1, filter2);
397        }
398    
399        /**
400         * Returns a filter that ORs the two specified filters.
401         * 
402         * @param filter1  the first filter
403         * @param filter2  the second filter
404         * @return a filter that ORs the two specified filters
405         * @see #or(IOFileFilter...)
406         * @see OrFileFilter
407         * @deprecated use {@link #or(IOFileFilter...)}
408         */
409        @Deprecated
410        public static IOFileFilter orFileFilter(IOFileFilter filter1, IOFileFilter filter2) {
411            return new OrFileFilter(filter1, filter2);
412        }
413    
414        /**
415         * Returns a filter that ANDs the specified filters.
416         * 
417         * @param filters the IOFileFilters that will be ANDed together.
418         * @return a filter that ANDs the specified filters
419         * 
420         * @throws IllegalArgumentException if the filters are null or contain a 
421         *         null value.
422         * @see AndFileFilter
423         * @since Commons IO 2.0
424         */
425        public static IOFileFilter and(IOFileFilter... filters) {
426            return new AndFileFilter(toList(filters));
427        }
428    
429        /**
430         * Returns a filter that ORs the specified filters.
431         * 
432         * @param filters the IOFileFilters that will be ORed together.
433         * @return a filter that ORs the specified filters
434         * 
435         * @throws IllegalArgumentException if the filters are null or contain a 
436         *         null value.
437         * @see OrFileFilter
438         * @since Commons IO 2.0
439         */
440        public static IOFileFilter or(IOFileFilter... filters) {
441            return new OrFileFilter(toList(filters));
442        }
443    
444        /**
445         * Create a List of file filters.
446         *
447         * @param filters The file filters
448         * @return The list of file filters
449         * @throws IllegalArgumentException if the filters are null or contain a 
450         *         null value.
451         * @since Commons IO 2.0
452         */
453        public static List<IOFileFilter> toList(IOFileFilter... filters) {
454            if (filters == null) {
455                throw new IllegalArgumentException("The filters must not be null");
456            }
457            List<IOFileFilter> list = new ArrayList<IOFileFilter>(filters.length);
458            for (int i = 0; i < filters.length; i++) {
459                if (filters[i] == null) {
460                    throw new IllegalArgumentException("The filter[" + i + "] is null");
461                }
462                list.add(filters[i]);
463            }
464            return list;
465        }
466    
467        /**
468         * Returns a filter that NOTs the specified filter.
469         * 
470         * @param filter  the filter to invert
471         * @return a filter that NOTs the specified filter
472         * @see NotFileFilter
473         */
474        public static IOFileFilter notFileFilter(IOFileFilter filter) {
475            return new NotFileFilter(filter);
476        }
477    
478        //-----------------------------------------------------------------------
479        /**
480         * Returns a filter that always returns true.
481         * 
482         * @return a true filter
483         * @see TrueFileFilter#TRUE
484         */
485        public static IOFileFilter trueFileFilter() {
486            return TrueFileFilter.TRUE;
487        }
488    
489        /**
490         * Returns a filter that always returns false.
491         * 
492         * @return a false filter
493         * @see FalseFileFilter#FALSE
494         */
495        public static IOFileFilter falseFileFilter() {
496            return FalseFileFilter.FALSE;
497        }
498        
499        //-----------------------------------------------------------------------
500        /**
501         * Returns an <code>IOFileFilter</code> that wraps the
502         * <code>FileFilter</code> instance.
503         * 
504         * @param filter  the filter to be wrapped
505         * @return a new filter that implements IOFileFilter
506         * @see DelegateFileFilter
507         */
508        public static IOFileFilter asFileFilter(FileFilter filter) {
509            return new DelegateFileFilter(filter);
510        }
511    
512        /**
513         * Returns an <code>IOFileFilter</code> that wraps the
514         * <code>FilenameFilter</code> instance.
515         * 
516         * @param filter  the filter to be wrapped
517         * @return a new filter that implements IOFileFilter
518         * @see DelegateFileFilter
519         */
520        public static IOFileFilter asFileFilter(FilenameFilter filter) {
521            return new DelegateFileFilter(filter);
522        }
523    
524        //-----------------------------------------------------------------------
525        /**
526         * Returns a filter that returns true if the file was last modified after
527         * the specified cutoff time.
528         *
529         * @param cutoff  the time threshold
530         * @return an appropriately configured age file filter
531         * @see AgeFileFilter
532         * @since Commons IO 1.2
533         */
534        public static IOFileFilter ageFileFilter(long cutoff) {
535            return new AgeFileFilter(cutoff);
536        }
537    
538        /**
539         * Returns a filter that filters files based on a cutoff time.
540         *
541         * @param cutoff  the time threshold
542         * @param acceptOlder  if true, older files get accepted, if false, newer
543         * @return an appropriately configured age file filter
544         * @see AgeFileFilter
545         * @since Commons IO 1.2
546         */
547        public static IOFileFilter ageFileFilter(long cutoff, boolean acceptOlder) {
548            return new AgeFileFilter(cutoff, acceptOlder);
549        }
550    
551        /**
552         * Returns a filter that returns true if the file was last modified after
553         * the specified cutoff date.
554         *
555         * @param cutoffDate  the time threshold
556         * @return an appropriately configured age file filter
557         * @see AgeFileFilter
558         * @since Commons IO 1.2
559         */
560        public static IOFileFilter ageFileFilter(Date cutoffDate) {
561            return new AgeFileFilter(cutoffDate);
562        }
563    
564        /**
565         * Returns a filter that filters files based on a cutoff date.
566         *
567         * @param cutoffDate  the time threshold
568         * @param acceptOlder  if true, older files get accepted, if false, newer
569         * @return an appropriately configured age file filter
570         * @see AgeFileFilter
571         * @since Commons IO 1.2
572         */
573        public static IOFileFilter ageFileFilter(Date cutoffDate, boolean acceptOlder) {
574            return new AgeFileFilter(cutoffDate, acceptOlder);
575        }
576    
577        /**
578         * Returns a filter that returns true if the file was last modified after
579         * the specified reference file.
580         *
581         * @param cutoffReference  the file whose last modification
582         *        time is usesd as the threshold age of the files
583         * @return an appropriately configured age file filter
584         * @see AgeFileFilter
585         * @since Commons IO 1.2
586         */
587        public static IOFileFilter ageFileFilter(File cutoffReference) {
588            return new AgeFileFilter(cutoffReference);
589        }
590    
591        /**
592         * Returns a filter that filters files based on a cutoff reference file.
593         *
594         * @param cutoffReference  the file whose last modification
595         *        time is usesd as the threshold age of the files
596         * @param acceptOlder  if true, older files get accepted, if false, newer
597         * @return an appropriately configured age file filter
598         * @see AgeFileFilter
599         * @since Commons IO 1.2
600         */
601        public static IOFileFilter ageFileFilter(File cutoffReference, boolean acceptOlder) {
602            return new AgeFileFilter(cutoffReference, acceptOlder);
603        }
604    
605        //-----------------------------------------------------------------------
606        /**
607         * Returns a filter that returns true if the file is bigger than a certain size.
608         *
609         * @param threshold  the file size threshold
610         * @return an appropriately configured SizeFileFilter
611         * @see SizeFileFilter
612         * @since Commons IO 1.2
613         */
614        public static IOFileFilter sizeFileFilter(long threshold) {
615            return new SizeFileFilter(threshold);
616        }
617    
618        /**
619         * Returns a filter that filters based on file size.
620         *
621         * @param threshold  the file size threshold
622         * @param acceptLarger  if true, larger files get accepted, if false, smaller
623         * @return an appropriately configured SizeFileFilter
624         * @see SizeFileFilter
625         * @since Commons IO 1.2
626         */
627        public static IOFileFilter sizeFileFilter(long threshold, boolean acceptLarger) {
628            return new SizeFileFilter(threshold, acceptLarger);
629        }
630    
631        /**
632         * Returns a filter that accepts files whose size is &gt;= minimum size
633         * and &lt;= maximum size.
634         *
635         * @param minSizeInclusive the minimum file size (inclusive)
636         * @param maxSizeInclusive the maximum file size (inclusive)
637         * @return an appropriately configured IOFileFilter
638         * @see SizeFileFilter
639         * @since Commons IO 1.3
640         */
641        public static IOFileFilter sizeRangeFileFilter(long minSizeInclusive, long maxSizeInclusive ) {
642            IOFileFilter minimumFilter = new SizeFileFilter(minSizeInclusive, true);
643            IOFileFilter maximumFilter = new SizeFileFilter(maxSizeInclusive + 1L, false);
644            return new AndFileFilter(minimumFilter, maximumFilter);
645        }
646        
647        /**
648         * Returns a filter that accepts files that begin with the provided magic
649         * number.
650         * 
651         * @param magicNumber the magic number (byte sequence) to match at the 
652         *        beginning of each file.
653         * 
654         * @return an IOFileFilter that accepts files beginning with the provided
655         *         magic number.
656         *         
657         * @throws IllegalArgumentException if <code>magicNumber</code> is 
658         *         <code>null</code> or the empty String.
659         * @see MagicNumberFileFilter
660         * @since Commons IO 2.0
661         */
662        public static IOFileFilter magicNumberFileFilter(String magicNumber) {
663            return new MagicNumberFileFilter(magicNumber);
664        }
665        
666        /**
667         * Returns a filter that accepts files that contains the provided magic
668         * number at a specified offset within the file.
669         * 
670         * @param magicNumber the magic number (byte sequence) to match at the 
671         *        provided offset in each file.
672         * @param offset the offset within the files to look for the magic number.
673         * 
674         * @return an IOFileFilter that accepts files containing the magic number
675         *         at the specified offset.
676         *         
677         * @throws IllegalArgumentException if <code>magicNumber</code> is 
678         *         <code>null</code> or the empty String, or if offset is a 
679         *         negative number.
680         * @see MagicNumberFileFilter
681         * @since Commons IO 2.0
682         */
683        public static IOFileFilter magicNumberFileFilter(String magicNumber, long offset) {
684            return new MagicNumberFileFilter(magicNumber, offset);
685        }
686        
687        /**
688         * Returns a filter that accepts files that begin with the provided magic
689         * number.
690         * 
691         * @param magicNumber the magic number (byte sequence) to match at the 
692         *        beginning of each file.
693         * 
694         * @return an IOFileFilter that accepts files beginning with the provided
695         *         magic number.
696         *         
697         * @throws IllegalArgumentException if <code>magicNumber</code> is 
698         *         <code>null</code> or is of length zero.
699         * @see MagicNumberFileFilter
700         * @since Commons IO 2.0
701         */
702        public static IOFileFilter magicNumberFileFilter(byte[] magicNumber) {
703            return new MagicNumberFileFilter(magicNumber);
704        }
705        
706        /**
707         * Returns a filter that accepts files that contains the provided magic
708         * number at a specified offset within the file.
709         * 
710         * @param magicNumber the magic number (byte sequence) to match at the 
711         *        provided offset in each file.
712         * @param offset the offset within the files to look for the magic number.
713         * 
714         * @return an IOFileFilter that accepts files containing the magic number
715         *         at the specified offset.
716         *         
717         * @throws IllegalArgumentException if <code>magicNumber</code> is 
718         *         <code>null</code>, or contains no bytes, or <code>offset</code> 
719         *         is a negative number.
720         * @see MagicNumberFileFilter
721         * @since Commons IO 2.0
722         */
723        public static IOFileFilter magicNumberFileFilter(byte[] magicNumber, long offset) {
724            return new MagicNumberFileFilter(magicNumber, offset);
725        }
726    
727        //-----------------------------------------------------------------------
728        /* Constructed on demand and then cached */
729        private static final IOFileFilter cvsFilter = notFileFilter(
730                and(directoryFileFilter(), nameFileFilter("CVS")));
731    
732        /* Constructed on demand and then cached */
733        private static final IOFileFilter svnFilter = notFileFilter(
734                and(directoryFileFilter(), nameFileFilter(".svn")));
735    
736        /**
737         * Decorates a filter to make it ignore CVS directories.
738         * Passing in <code>null</code> will return a filter that accepts everything
739         * except CVS directories.
740         * 
741         * @param filter  the filter to decorate, null means an unrestricted filter
742         * @return the decorated filter, never null
743         * @since Commons IO 1.1 (method existed but had bug in 1.0)
744         */
745        public static IOFileFilter makeCVSAware(IOFileFilter filter) {
746            if (filter == null) {
747                return cvsFilter;
748            } else {
749                return and(filter, cvsFilter);
750            }
751        }
752    
753        /**
754         * Decorates a filter to make it ignore SVN directories.
755         * Passing in <code>null</code> will return a filter that accepts everything
756         * except SVN directories.
757         * 
758         * @param filter  the filter to decorate, null means an unrestricted filter
759         * @return the decorated filter, never null
760         * @since Commons IO 1.1
761         */
762        public static IOFileFilter makeSVNAware(IOFileFilter filter) {
763            if (filter == null) {
764                return svnFilter;
765            } else {
766                return and(filter, svnFilter);
767            }
768        }
769    
770        //-----------------------------------------------------------------------
771        /**
772         * Decorates a filter so that it only applies to directories and not to files.
773         * 
774         * @param filter  the filter to decorate, null means an unrestricted filter
775         * @return the decorated filter, never null
776         * @see DirectoryFileFilter#DIRECTORY
777         * @since Commons IO 1.3
778         */
779        public static IOFileFilter makeDirectoryOnly(IOFileFilter filter) {
780            if (filter == null) {
781                return DirectoryFileFilter.DIRECTORY;
782            }
783            return new AndFileFilter(DirectoryFileFilter.DIRECTORY, filter);
784        }
785    
786        /**
787         * Decorates a filter so that it only applies to files and not to directories.
788         * 
789         * @param filter  the filter to decorate, null means an unrestricted filter
790         * @return the decorated filter, never null
791         * @see FileFileFilter#FILE
792         * @since Commons IO 1.3
793         */
794        public static IOFileFilter makeFileOnly(IOFileFilter filter) {
795            if (filter == null) {
796                return FileFileFilter.FILE;
797            }
798            return new AndFileFilter(FileFileFilter.FILE, filter);
799        }
800    
801    }