View Javadoc

1   /*
2    * FCKeditor - The text editor for Internet - http://www.fckeditor.net
3    * Copyright (C) 2004-2010 Frederico Caldeira Knabben
4    * 
5    * == BEGIN LICENSE ==
6    * 
7    * Licensed under the terms of any of the following licenses at your
8    * choice:
9    * 
10   *  - GNU General Public License Version 2 or later (the "GPL")
11   *    http://www.gnu.org/licenses/gpl.html
12   * 
13   *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
14   *    http://www.gnu.org/licenses/lgpl.html
15   * 
16   *  - Mozilla Public License Version 1.1 or later (the "MPL")
17   *    http://www.mozilla.org/MPL/MPL-1.1.html
18   * 
19   * == END LICENSE ==
20   */
21  package net.fckeditor.tool;
22  
23  import java.io.File;
24  import java.io.InputStream;
25  import java.util.regex.Pattern;
26  
27  import net.fckeditor.handlers.PropertiesLoader;
28  
29  import org.apache.commons.io.FilenameUtils;
30  import org.devlib.schmidt.imageinfo.ImageInfo;
31  
32  /**
33   * Static helper methods for files.
34   * 
35   * @version $Id: UtilsFile.java 4785 2009-12-21 20:10:28Z mosipov $
36   */
37  public class UtilsFile {
38  	
39  	protected static final Pattern ILLEGAL_CURRENT_FOLDER_PATTERN = Pattern
40  			.compile("^[^/]|[^/]$|/\\.{1,2}|\\\\|\\||:|\\?|\\*|\"|<|>|\\p{Cntrl}");
41  
42  	/**
43  	 * Sanitizes a filename from certain chars.<br />
44  	 * 
45  	 * This method enforces the <code>forceSingleExtension</code> property and
46  	 * then replaces all occurrences of \, /, |, :, ?, *, &quot;, &lt;, &gt;,
47  	 * control chars by _ (underscore).
48  	 * 
49  	 * @param filename
50  	 *            a potentially 'malicious' filename
51  	 * @return sanitized filename
52  	 */
53  	public static String sanitizeFileName(final String filename) {
54  
55  		if (Utils.isEmpty(filename))
56  			return filename;
57  
58  		String name = (PropertiesLoader.isForceSingleExtension()) ? UtilsFile
59  				.forceSingleExtension(filename) : filename;
60  
61  		// Remove \ / | : ? * " < > 'Control Chars' with _
62  		return name.replaceAll("\\\\|/|\\||:|\\?|\\*|\"|<|>|\\p{Cntrl}", "_");
63  	}
64  
65  	/**
66  	 * Sanitizes a folder name from certain chars.<br />
67  	 * 
68  	 * This method replaces all occurrences of \, /, |, :, ?, *, &quot;, &lt;,
69  	 * &gt;, control chars by _ (underscore).
70  	 * 
71  	 * @param folderName
72  	 *            a potentially 'malicious' folder name
73  	 * @return sanitized folder name
74  	 */
75  	public static String sanitizeFolderName(final String folderName) {
76  
77  		if (Utils.isEmpty(folderName))
78  			return folderName;
79  
80  		// Remove . \ / | : ? * " < > 'Control Chars' with _
81  		return folderName.replaceAll(
82  				"\\.|\\\\|/|\\||:|\\?|\\*|\"|<|>|\\p{Cntrl}", "_");
83  	}
84  
85  	/**
86  	 * Checks if the underlying input stream contains an image.
87  	 * 
88  	 * @param in
89  	 *            input stream of an image
90  	 * @return <code>true</code> if the underlying input stream contains an
91  	 *         image, else <code>false</code>
92  	 */
93  	public static boolean isImage(final InputStream in) {
94  		ImageInfo ii = new ImageInfo();
95  		ii.setInput(in);
96  		return ii.check();
97  	}
98  
99  	/**
100 	 * Checks whether a path complies with the FCKeditor File Browser <a href="http://docs.fckeditor.net/FCKeditor_2.x/Developers_Guide/Server_Side_Integration#File_Browser_Requests"
101 	 * target="_blank">rules</a>.
102 	 * 
103 	 * @param path
104 	 *            a potentially 'malicious' path
105 	 * @return <code>true</code> if path complies with the rules, else
106 	 *         <code>false</code>
107 	 */
108 	public static boolean isValidPath(final String path) {
109 		if (Utils.isEmpty(path))
110 			return false;
111 
112 		if (ILLEGAL_CURRENT_FOLDER_PATTERN.matcher(path).find())
113 			return false;
114 		
115 		return true;
116 	}
117 
118 	/**
119 	 * Replaces all dots in a filename with underscores except the last one.
120 	 * 
121 	 * @param filename
122 	 *            filename to sanitize
123 	 * @return string with a single dot only
124 	 */
125 	public static String forceSingleExtension(final String filename) {
126 		return filename.replaceAll("\\.(?![^.]+$)", "_");
127 	}
128 
129 	/**
130 	 * Checks if a filename contains more than one dot.
131 	 * 
132 	 * @param filename
133 	 *            filename to check
134 	 * @return <code>true</code> if filename contains severals dots, else
135 	 *         <code>false</code>
136 	 */
137 	public static boolean isSingleExtension(final String filename) {
138 		return filename.matches("[^\\.]+\\.[^\\.]+");
139 	}
140 
141 	/**
142 	 * Checks a directory for existence and creates it if non-existent.
143 	 * 
144 	 * @param dir
145 	 *            directory to check/create
146 	 */
147 	public static void checkDirAndCreate(File dir) {
148 		if (!dir.exists())
149 			dir.mkdirs();
150 	}
151 
152 	/**
153 	 * Iterates over a base name and returns the first non-existent file.<br />
154 	 * This method extracts a file's base name, iterates over it until the first
155 	 * non-existent appearance with <code>basename(n).ext</code>. Where n is a
156 	 * positive integer starting from one.
157 	 * 
158 	 * @param file
159 	 *            base file
160 	 * @return first non-existent file
161 	 */
162 	public static File getUniqueFile(final File file) {
163 		if (!file.exists())
164 			return file;
165 
166 		File tmpFile = new File(file.getAbsolutePath());
167 		File parentDir = tmpFile.getParentFile();
168 		int count = 1;
169 		String extension = FilenameUtils.getExtension(tmpFile.getName());
170 		String baseName = FilenameUtils.getBaseName(tmpFile.getName());
171 		do {
172 			tmpFile = new File(parentDir, baseName + "(" + count++ + ")."
173 					+ extension);
174 		} while (tmpFile.exists());
175 		return tmpFile;
176 	}
177 }