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.local; 018 019import org.apache.commons.vfs2.FileName; 020import org.apache.commons.vfs2.FileSystemException; 021import org.apache.commons.vfs2.FileType; 022 023/** 024 * A parser for Windows file names. 025 */ 026public class WindowsFileNameParser extends LocalFileNameParser { 027 028 /** 029 * Constructs a new instance. 030 */ 031 public WindowsFileNameParser() { 032 // empty 033 } 034 035 @Override 036 protected FileName createFileName(final String scheme, final String rootFile, final String path, 037 final FileType type) { 038 return new WindowsFileName(scheme, rootFile, path, type); 039 } 040 041 /** 042 * Extracts a drive prefix from a path. Leading '/' chars have been removed. 043 */ 044 private String extractDrivePrefix(final StringBuilder name) { 045 // Looking for <letter> ':' '/' 046 if (name.length() < 3) { 047 // Too short 048 return null; 049 } 050 final char ch = name.charAt(0); 051 if (ch == '/' || ch == ':') { 052 // Missing drive letter 053 return null; 054 } 055 if (name.charAt(1) != ':') { 056 // Missing ':' 057 return null; 058 } 059 if (name.charAt(2) != '/') { 060 // Missing separator 061 return null; 062 } 063 064 final String prefix = name.substring(0, 2); 065 name.delete(0, 2); 066 067 return prefix.intern(); 068 } 069 070 /** 071 * Pops the root prefix off a URI, which has had the scheme removed. 072 */ 073 @Override 074 protected String extractRootPrefix(final String uri, final StringBuilder name) throws FileSystemException { 075 return extractWindowsRootPrefix(uri, name); 076 } 077 078 /** 079 * Extracts a UNC name from a path. Leading '/' chars have been removed. 080 */ 081 private String extractUNCPrefix(final String uri, final StringBuilder name) throws FileSystemException { 082 // Looking for <name> '/' <name> ( '/' | <end> ) 083 084 // Look for first separator 085 final int maxpos = name.length(); 086 int pos = 0; 087 while (pos < maxpos && name.charAt(pos) != '/') { 088 pos++; 089 } 090 pos++; 091 if (pos >= maxpos) { 092 throw new FileSystemException("vfs.provider.local/missing-share-name.error", uri); 093 } 094 095 // Now have <name> '/' 096 final int startShareName = pos; 097 while (pos < maxpos && name.charAt(pos) != '/') { 098 pos++; 099 } 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}