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      /**
29       * Constructs a new instance.
30       */
31      public WindowsFileNameParser() {
32          // empty
33      }
34  
35      @Override
36      protected FileName createFileName(final String scheme, final String rootFile, final String path,
37              final FileType type) {
38          return new WindowsFileName(scheme, rootFile, path, type);
39      }
40  
41      /**
42       * Extracts a drive prefix from a path. Leading '/' chars have been removed.
43       */
44      private String extractDrivePrefix(final StringBuilder name) {
45          // Looking for <letter> ':' '/'
46          if (name.length() < 3) {
47              // Too short
48              return null;
49          }
50          final char ch = name.charAt(0);
51          if (ch == '/' || ch == ':') {
52              // Missing drive letter
53              return null;
54          }
55          if (name.charAt(1) != ':') {
56              // Missing ':'
57              return null;
58          }
59          if (name.charAt(2) != '/') {
60              // Missing separator
61              return null;
62          }
63  
64          final String prefix = name.substring(0, 2);
65          name.delete(0, 2);
66  
67          return prefix.intern();
68      }
69  
70      /**
71       * Pops the root prefix off a URI, which has had the scheme removed.
72       */
73      @Override
74      protected String extractRootPrefix(final String uri, final StringBuilder name) throws FileSystemException {
75          return extractWindowsRootPrefix(uri, name);
76      }
77  
78      /**
79       * Extracts a UNC name from a path. Leading '/' chars have been removed.
80       */
81      private String extractUNCPrefix(final String uri, final StringBuilder name) throws FileSystemException {
82          // Looking for <name> '/' <name> ( '/' | <end> )
83  
84          // Look for first separator
85          final int maxpos = name.length();
86          int pos = 0;
87          while (pos < maxpos && name.charAt(pos) != '/') {
88              pos++;
89          }
90          pos++;
91          if (pos >= maxpos) {
92              throw new FileSystemException("vfs.provider.local/missing-share-name.error", uri);
93          }
94  
95          // Now have <name> '/'
96          final int startShareName = pos;
97          while (pos < maxpos && name.charAt(pos) != '/') {
98              pos++;
99          }
100         if (pos == startShareName) {
101             throw new FileSystemException("vfs.provider.local/missing-share-name.error", uri);
102         }
103 
104         // Now have <name> '/' <name> ( '/' | <end> )
105         final String prefix = name.substring(0, pos);
106         name.delete(0, pos);
107         return prefix;
108     }
109 
110     /**
111      * Extracts a Windows root prefix from a name.
112      */
113     private String extractWindowsRootPrefix(final String uri, final StringBuilder name) throws FileSystemException {
114         // Looking for:
115         // ('/'){0, 3} <letter> ':' '/'
116         // ['/'] '//' <name> '/' <name> ( '/' | <end> )
117 
118         // Skip over first 4 (unc) leading '/' chars
119         int startPos = 0;
120         final int maxlen = Math.min(4, name.length());
121         while (startPos < maxlen && name.charAt(startPos) == '/') {
122             startPos++;
123         }
124         if (startPos == maxlen && name.length() > startPos + 1 && name.charAt(startPos + 1) == '/') {
125             // Too many '/'
126             throw new FileSystemException("vfs.provider.local/not-absolute-file-name.error", uri);
127         }
128         name.delete(0, startPos);
129 
130         // Look for drive name
131         final String driveName = extractDrivePrefix(name);
132         if (driveName != null) {
133             return driveName;
134         }
135 
136         // Look for UNC name
137         if (startPos < 2) {
138             throw new FileSystemException("vfs.provider.local/not-absolute-file-name.error", uri);
139         }
140 
141         return "//" + extractUNCPrefix(uri, name);
142     }
143 }