001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.vfs2.provider.url; 018 019import org.apache.commons.vfs2.FileName; 020import org.apache.commons.vfs2.FileSystemException; 021import org.apache.commons.vfs2.provider.AbstractFileNameParser; 022import org.apache.commons.vfs2.provider.URLFileName; 023import org.apache.commons.vfs2.provider.URLFileNameParser; 024import org.apache.commons.vfs2.provider.VfsComponentContext; 025import org.apache.commons.vfs2.provider.local.GenericFileNameParser; 026 027/** 028 * Implementation for any java.net.url based file system. 029 * <p> 030 * Composite of URLFilenameParser and GenericFilenameParser 031 */ 032public class UrlFileNameParser extends AbstractFileNameParser { 033 034 private final URLFileNameParser urlFileNameParser = new URLFileNameParser(80); 035 private final GenericFileNameParser genericFileNameParser = new GenericFileNameParser(); 036 037 /** 038 * Constructs a new instance. 039 */ 040 public UrlFileNameParser() { 041 } 042 043 /** 044 * This method counts the slashes after the scheme. 045 * 046 * @param fileName The file name. 047 * @return number of slashes 048 */ 049 protected int countSlashes(final String fileName) { 050 int state = 0; 051 int nuofSlash = 0; 052 for (int pos = 0; pos < fileName.length(); pos++) { 053 final char c = fileName.charAt(pos); 054 if (state == 0) { 055 if (c >= 'a' && c <= 'z') { 056 continue; 057 } 058 if (c == ':') { 059 state++; 060 continue; 061 } 062 } else if (state == 1) { 063 if (c != '/') { 064 return nuofSlash; 065 } 066 nuofSlash++; 067 } 068 } 069 return nuofSlash; 070 } 071 072 @Override 073 public boolean encodeCharacter(final char ch) { 074 return super.encodeCharacter(ch) || ch == '?'; 075 } 076 077 /** 078 * Guess if the given file name is a URL with host or not. 079 * <p> 080 * VFS treats such URLs differently. 081 * </p> 082 * <p> 083 * A file name is URL-based if the base is a {@code URLFileName} or there are only 2 slashes after the scheme. e.g: 084 * {@code http://host/path}, {@code file:/path/to/file}, {@code file:///path/to/file}. 085 * </p> 086 * 087 * @param base The file name is relative to this base. 088 * @param fileName The file name. 089 * @return true if file name contains two slashes or base was URLFileName. 090 */ 091 protected boolean isUrlBased(final FileName base, final String fileName) { 092 if (base instanceof URLFileName) { 093 return true; 094 } 095 096 return countSlashes(fileName) == 2; 097 } 098 099 /** 100 * Parse a URI. 101 * 102 * @param context The component context. 103 * @param base The base FileName. 104 * @param uri The target file name. 105 * @return The FileName. 106 * @throws FileSystemException if an error occurs 107 */ 108 @Override 109 public FileName parseUri(final VfsComponentContext context, final FileName base, final String uri) 110 throws FileSystemException { 111 if (isUrlBased(base, uri)) { 112 return urlFileNameParser.parseUri(context, base, uri); 113 } 114 return genericFileNameParser.parseUri(context, base, uri); 115 } 116}