1 /*
2  * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.nio.fs;
27 
28 import java.nio.file.Path;
29 import java.nio.file.spi.FileTypeDetector;
30 import java.util.Locale;
31 import java.io.IOException;
32 
33 /**
34  * Base implementation of FileTypeDetector
35  */
36 
37 public abstract class AbstractFileTypeDetector
38     extends FileTypeDetector
39 {
AbstractFileTypeDetector()40     protected AbstractFileTypeDetector() {
41         super();
42     }
43 
44     /**
45      * Invokes the appropriate probe method to guess a file's content type,
46      * and checks that the content type's syntax is valid.
47      */
48     @Override
probeContentType(Path file)49     public final String probeContentType(Path file) throws IOException {
50         if (file == null)
51             throw new NullPointerException("'file' is null");
52         String result = implProbeContentType(file);
53         return (result == null) ? null : parse(result);
54     }
55 
56     /**
57      * Probes the given file to guess its content type.
58      */
implProbeContentType(Path file)59     protected abstract String implProbeContentType(Path file)
60         throws IOException;
61 
62     /**
63      * Parses a candidate content type into its type and subtype, returning
64      * null if either token is invalid.
65      */
parse(String s)66     private static String parse(String s) {
67         int slash = s.indexOf('/');
68         int semicolon = s.indexOf(';');
69         if (slash < 0)
70             return null;  // no subtype
71         String type = s.substring(0, slash).trim().toLowerCase(Locale.ENGLISH);
72         if (!isValidToken(type))
73             return null;  // invalid type
74         String subtype = (semicolon < 0) ? s.substring(slash + 1) :
75             s.substring(slash + 1, semicolon);
76         subtype = subtype.trim().toLowerCase(Locale.ENGLISH);
77         if (!isValidToken(subtype))
78             return null;  // invalid subtype
79         StringBuilder sb = new StringBuilder(type.length() + subtype.length() + 1);
80         sb.append(type);
81         sb.append('/');
82         sb.append(subtype);
83         return sb.toString();
84     }
85 
86     /**
87      * Special characters
88      */
89     private static final String TSPECIALS = "()<>@,;:/[]?=\\\"";
90 
91     /**
92      * Returns true if the character is a valid token character.
93      */
isTokenChar(char c)94     private static boolean isTokenChar(char c) {
95         return (c > 040) && (c < 0177) && (TSPECIALS.indexOf(c) < 0);
96     }
97 
98     /**
99      * Returns true if the given string is a legal type or subtype.
100      */
isValidToken(String s)101     private static boolean isValidToken(String s) {
102         int len = s.length();
103         if (len == 0)
104             return false;
105         for (int i = 0; i < len; i++) {
106             if (!isTokenChar(s.charAt(i)))
107                 return false;
108         }
109         return true;
110     }
111 }
112