001/*
002 * Syncany, www.syncany.org
003 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com>
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package org.syncany.config;
019
020import java.io.File;
021import java.io.FileNotFoundException;
022import java.util.HashSet;
023import java.util.Scanner;
024import java.util.Set;
025import java.util.logging.Level;
026import java.util.logging.Logger;
027
028/**
029 * This class serves as a container of patterns of filenames
030 * that should be ignored.
031 *
032 * @author Pim Otte
033 */
034public class IgnoredFiles {
035        private static final Logger logger = Logger.getLogger(ConfigHelper.class.getSimpleName());
036
037        private Set<String> ignorePatterns;
038        private Set<String> ignorePaths;
039        private File ignoreFile;
040
041        public IgnoredFiles(File ignoreFile) {
042                this.ignoreFile = ignoreFile;
043                this.ignorePatterns = new HashSet<String>();
044                this.ignorePaths = new HashSet<String>();
045
046                loadPatterns();
047        }
048
049        /**
050         * Method to check whether a file should be ignored.
051         * Should only be called at indexing time.
052         */
053        public boolean isFileIgnored(String filePath, String fileName) {
054                // Check all exact paths
055                for (String path : ignorePaths) {
056                        if (path.equals(filePath)) {
057                                return true;
058                        }
059                }
060
061        // Check all recursive
062                for (String path : ignorePaths) {
063                        if (path.equals(fileName)) {
064                                return true;
065                        }
066                }
067
068                // Check all regular expressions
069                for (String pattern : ignorePatterns) {
070                        if (filePath.matches(pattern)) {
071                                return true;
072                        }
073                }
074
075                return false;
076        }
077
078        public void loadPatterns() {
079                if (ignoreFile != null && ignoreFile.exists()) {
080                        try {
081                                Scanner scanner = new Scanner(ignoreFile);
082
083                                while (scanner.hasNextLine()) {
084                                        String ignorePatternLine = scanner.nextLine().trim();
085
086                                        if (!ignorePatternLine.isEmpty()) {
087                                                parseIgnoreFileLine(ignorePatternLine);
088                                        }
089                                }
090
091                                scanner.close();
092                        }
093                        catch (FileNotFoundException e) {
094                                logger.log(Level.INFO, "Ignore file not found (existed before).", e);
095                        }
096                }
097                else {
098                        // In case the ignoreFile has been deleted, reset patterns
099                        ignorePatterns = new HashSet<String>();
100                        ignorePaths = new HashSet<String>();
101                }
102        }
103
104        private void parseIgnoreFileLine(String ignorePattern) {
105                if (ignorePattern.startsWith("regex:")) {
106                        // Chop off regex: indicator
107                        ignorePatterns.add(ignorePattern.substring(6));
108                }
109                else {
110                        if (ignorePattern.contains("*") || ignorePattern.contains("?")) {
111                                // wildcards handling, converting them to regexps
112                                ignorePatterns.add(convertWildcardsToRegexp(ignorePattern));
113                        }
114                        else {
115                                ignorePaths.add(ignorePattern);
116                        }
117                }
118        }
119
120        private static String convertWildcardsToRegexp(String in) {
121                StringBuilder out = new StringBuilder("^");
122
123                for (int i = 0; i < in.length(); ++i) {
124                        char c = in.charAt(i);
125
126                        switch (c) {
127                        case '*':
128                                out.append(".*");
129                                break;
130                        case '?':
131                                out.append('.');
132                                break;
133                        case '.':
134                        case '$':
135                        case '^':
136                        case '{':
137                        case '}':
138                        case '[':
139                        case ']':
140                        case '(':
141                        case ')':
142                        case '|':
143                        case '+':
144                        case '\\':
145                                out.append('\\');
146                                out.append(c);
147                                break;
148                        default:
149                                out.append(c);
150                        }
151                }
152
153                out.append('$');
154
155                return out.toString();
156        }
157}