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;
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   * Implementation for layered file systems.
25   * <p>
26   * Additionally encodes the '!' character.
27   * </p>
28   */
29  public class LayeredFileNameParser extends AbstractFileNameParser {
30  
31      private static final LayeredFileNameParser INSTANCE = new LayeredFileNameParser();
32  
33      /**
34       * Gets the singleton instance.
35       *
36       * @return the singleton instance.
37       */
38      public static LayeredFileNameParser getInstance() {
39          return INSTANCE;
40      }
41  
42      /**
43       * Constructs a new instance.
44       */
45      public LayeredFileNameParser() {
46          // empty
47      }
48  
49      /**
50       * Determines if a character should be encoded.
51       *
52       * @param ch The character to check.
53       * @return true if the character should be encoded.
54       */
55      @Override
56      public boolean encodeCharacter(final char ch) {
57          return super.encodeCharacter(ch) || ch == LayeredFileName.LAYER_SEPARATOR;
58      }
59  
60      /**
61       * Pops the root prefix off a URI, which has had the scheme removed.
62       *
63       * @param uri string builder which gets modified.
64       * @return the extracted root name.
65       */
66      protected String extractRootName(final StringBuilder uri) {
67          // Looking for <name>!<abspath> (staring at the end)
68          final int maxlen = uri.length();
69          int pos = maxlen - 1;
70          while (pos > 0 && uri.charAt(pos) != LayeredFileName.LAYER_SEPARATOR) {
71              pos--;
72          }
73  
74          if (pos == 0 && uri.charAt(pos) != LayeredFileName.LAYER_SEPARATOR) {
75              // not ! found, so take the whole path a root
76              // e.g. zip:/my/zip/file.zip
77              pos = maxlen;
78          }
79  
80          // Extract the name
81          final String prefix = uri.substring(0, pos);
82          if (pos < maxlen) {
83              uri.delete(0, pos + 1);
84          } else {
85              uri.setLength(0);
86          }
87  
88          return prefix;
89      }
90  
91      /**
92       * Parses the base and name into a FileName.
93       *
94       * @param context The component context.
95       * @param baseFileName The base FileName.
96       * @param fileName name The target file name.
97       * @return The constructed FileName.
98       * @throws FileSystemException if an error occurs.
99       */
100     @Override
101     public FileName parseUri(final VfsComponentContext context, final FileName baseFileName, final String fileName)
102             throws FileSystemException {
103         final StringBuilder name = new StringBuilder();
104 
105         // Extract the scheme
106         final String scheme = UriParser.extractScheme(context.getFileSystemManager().getSchemes(), fileName, name);
107 
108         // Extract the Layered file URI
109         final String rootUriName = extractRootName(name);
110         FileName rootUri = null;
111         if (rootUriName != null) {
112             rootUri = context.parseURI(rootUriName);
113         }
114 
115         // Decode and normalise the path
116         UriParser.canonicalizePath(name, 0, name.length(), this);
117         UriParser.fixSeparators(name);
118         final FileType fileType = UriParser.normalisePath(name);
119         final String path = name.toString();
120 
121         return new LayeredFileName(scheme, rootUri, path, fileType);
122     }
123 
124 }