1 /*
2 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
3 * Copyright (C) 2004-2009 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 3876 2009-07-13 18:27:07Z 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 \, /, |, :, ?, *, ", <, >,
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 \, /, |, :, ?, *, ", <,
69 * >, 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 }