1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.tika.mime;
18
19
20 import java.util.Comparator;
21 import java.util.HashMap;
22 import java.util.Map;
23 import java.util.SortedMap;
24 import java.util.TreeMap;
25
26
27
28
29 class Patterns {
30
31
32
33
34 private final Map<String, MimeType> names = new HashMap<String, MimeType>();
35
36
37
38
39 private final Map<String, MimeType> extensions =
40 new HashMap<String, MimeType>();
41
42 private int minExtensionLength = Integer.MAX_VALUE;
43
44 private int maxExtensionLength = 0;
45
46
47
48
49 private final SortedMap<String, MimeType> globs =
50 new TreeMap<String, MimeType>(new Comparator<String>() {
51 public int compare(String a, String b) {
52 int diff = b.length() - a.length();
53 if (diff == 0) {
54 diff = a.compareTo(b);
55 }
56 return diff;
57 }
58 });
59
60
61 public void add(String pattern, MimeType type) throws MimeTypeException {
62 this.add(pattern, false, type);
63 }
64
65 public void add(String pattern, boolean isJavaRegex, MimeType type)
66 throws MimeTypeException {
67 if (pattern == null || type == null) {
68 throw new IllegalArgumentException(
69 "Pattern and/or mime type is missing");
70 }
71
72 if (isJavaRegex) {
73
74
75 addGlob(pattern, type);
76 } else {
77
78 if (pattern.indexOf('*') == -1 && pattern.indexOf('?') == -1
79 && pattern.indexOf('[') == -1) {
80 addName(pattern, type);
81 } else if (pattern.startsWith("*") && pattern.indexOf('*', 1) == -1
82 && pattern.indexOf('?') == -1 && pattern.indexOf('[') == -1) {
83 addExtension(pattern.substring(1), type);
84 } else {
85 addGlob(compile(pattern), type);
86 }
87 }
88 }
89
90 private void addName(String name, MimeType type) throws MimeTypeException {
91 MimeType previous = names.get(name);
92 if (previous == null || previous.isDescendantOf(type)) {
93 names.put(name, type);
94 } else if (previous == type || type.isDescendantOf(previous)) {
95
96 } else {
97 throw new MimeTypeException("Conflicting name pattern: " + name);
98 }
99 }
100
101 private void addExtension(String extension, MimeType type)
102 throws MimeTypeException {
103 MimeType previous = extensions.get(extension);
104 if (previous == null || previous.isDescendantOf(type)) {
105 extensions.put(extension, type);
106 int length = extension.length();
107 minExtensionLength = Math.min(minExtensionLength, length);
108 maxExtensionLength = Math.max(maxExtensionLength, length);
109 } else if (previous == type || type.isDescendantOf(previous)) {
110
111 } else {
112 throw new MimeTypeException(
113 "Conflicting extension pattern: " + extension);
114 }
115 }
116
117 private void addGlob(String glob, MimeType type)
118 throws MimeTypeException {
119 MimeType previous = globs.get(glob);
120 if (previous == null || previous.isDescendantOf(type)) {
121 globs.put(glob, type);
122 } else if (previous == type || type.isDescendantOf(previous)) {
123
124 } else {
125 throw new MimeTypeException("Conflicting glob pattern: " + glob);
126 }
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 public MimeType matches(String name) {
144 if (name == null) {
145 throw new IllegalArgumentException("Name is missing");
146 }
147
148
149 if (names.containsKey(name)) {
150 return names.get(name);
151 }
152
153
154 int maxLength = Math.min(maxExtensionLength, name.length());
155 for (int n = maxLength; n >= minExtensionLength; n--) {
156 String extension = name.substring(name.length() - n);
157 if (extensions.containsKey(extension)) {
158 return extensions.get(extension);
159 }
160 }
161
162
163 for (Map.Entry<String, MimeType> entry : globs.entrySet()) {
164 if (name.matches(entry.getKey())) {
165 return entry.getValue();
166 }
167 }
168
169 return null;
170 }
171
172 private String compile(String glob) {
173 StringBuilder pattern = new StringBuilder();
174 pattern.append("\\A");
175 for (int i = 0; i < glob.length(); i++) {
176 char ch = glob.charAt(i);
177 if (ch == '?') {
178 pattern.append('.');
179 } else if (ch == '*') {
180 pattern.append(".*");
181 } else if ("\\[]^.-$+(){}|".indexOf(ch) != -1) {
182 pattern.append('\\');
183 pattern.append(ch);
184 } else {
185 pattern.append(ch);
186 }
187 }
188 pattern.append("\\z");
189 return pattern.toString();
190 }
191
192 }