View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.vfs2.provider.local;
18  
19  import org.apache.commons.vfs2.FileName;
20  import org.apache.commons.vfs2.FileSystemException;
21  import org.apache.commons.vfs2.FileType;
22  
23  /**
24   * A parser for Windows file names.
25   */
26  public class WindowsFileNameParser extends LocalFileNameParser {
27  
28      @Override
29      protected FileName createFileName(final String scheme, final String rootFile, final String path,
30              final FileType type) {
31          return new WindowsFileName(scheme, rootFile, path, type);
32      }
33  
34      /**
35       * Extracts a drive prefix from a path. Leading '/' chars have been removed.
36       */
37      private String extractDrivePrefix(final StringBuilder name) {
38          // Looking for <letter> ':' '/'
39          if (name.length() < 3) {
40              // Too short
41              return null;
42          }
43          final char ch = name.charAt(0);
44          if (ch == '/' || ch == ':') {
45              // Missing drive letter
46              return null;
47          }
48          if (name.charAt(1) != ':') {
49              // Missing ':'
50              return null;
51          }
52          if (name.charAt(2) != '/') {
53              // Missing separator
54              return null;
55          }
56  
57          final String prefix = name.substring(0, 2);
58          name.delete(0, 2);
59  
60          return prefix.intern();
61      }
62  
63      /**
64       * Pops the root prefix off a URI, which has had the scheme removed.
65       */
66      @Override
67      protected String extractRootPrefix(final String uri, final StringBuilder name) throws FileSystemException {
68          return extractWindowsRootPrefix(uri, name);
69      }
70  
71      /**
72       * Extracts a UNC name from a path. Leading '/' chars have been removed.
73       */
74      private String extractUNCPrefix(final String uri, final StringBuilder name) throws FileSystemException {
75          // Looking for <name> '/' <name> ( '/' | <end> )
76  
77          // Look for first separator
78          final int maxpos = name.length();
79          int pos = 0;
80          for (; pos < maxpos && name.charAt(pos) != '/'; pos++) {
81              // empty
82          }
83          pos++;
84          if (pos >= maxpos) {
85              throw new FileSystemException("vfs.provider.local/missing-share-name.error", uri);
86          }
87  
88          // Now have <name> '/'
89          final int startShareName = pos;
90          for (; pos < maxpos && name.charAt(pos) != '/'; pos++) {
91              // empty
92          }
93          if (pos == startShareName) {
94              throw new FileSystemException("vfs.provider.local/missing-share-name.error", uri);
95          }
96  
97          // Now have <name> '/' <name> ( '/' | <end> )
98          final String prefix = name.substring(0, pos);
99          name.delete(0, pos);
100         return prefix;
101     }
102 
103     /**
104      * Extracts a Windows root prefix from a name.
105      */
106     private String extractWindowsRootPrefix(final String uri, final StringBuilder name) throws FileSystemException {
107         // Looking for:
108         // ('/'){0, 3} <letter> ':' '/'
109         // ['/'] '//' <name> '/' <name> ( '/' | <end> )
110 
111         // Skip over first 4 (unc) leading '/' chars
112         int startPos = 0;
113         final int maxlen = Math.min(4, name.length());
114         for (; startPos < maxlen && name.charAt(startPos) == '/'; startPos++) {
115             // empty
116         }
117         if (startPos == maxlen && name.length() > (startPos + 1) && name.charAt(startPos + 1) == '/') {
118             // Too many '/'
119             throw new FileSystemException("vfs.provider.local/not-absolute-file-name.error", uri);
120         }
121         name.delete(0, startPos);
122 
123         // Look for drive name
124         final String driveName = extractDrivePrefix(name);
125         if (driveName != null) {
126             return driveName;
127         }
128 
129         // Look for UNC name
130         if (startPos < 2) {
131             throw new FileSystemException("vfs.provider.local/not-absolute-file-name.error", uri);
132         }
133 
134         return "//" + extractUNCPrefix(uri, name);
135     }
136 }