/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package org.apache.tools.ant.types.selectors;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.util.FileUtils;

Container for a path that has been split into its components.
Since:1.8.0
/** * Container for a path that has been split into its components. * @since 1.8.0 */
public class TokenizedPath {
Instance that holds no tokens at all.
/** * Instance that holds no tokens at all. */
public static final TokenizedPath EMPTY_PATH = new TokenizedPath("", new String[0]);
Helper.
/** Helper. */
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
iterations for case-sensitive scanning.
/** iterations for case-sensitive scanning. */
private static final boolean[] CS_SCAN_ONLY = new boolean[] {true};
iterations for non-case-sensitive scanning.
/** iterations for non-case-sensitive scanning. */
private static final boolean[] CS_THEN_NON_CS = new boolean[] {true, false}; private final String path; private final String[] tokenizedPath;
Initialize the TokenizedPath by parsing it.
Params:
  • path – The path to tokenize. Must not be null.
/** * Initialize the TokenizedPath by parsing it. * @param path The path to tokenize. Must not be * <code>null</code>. */
public TokenizedPath(String path) { this(path, SelectorUtils.tokenizePathAsArray(path)); }
Creates a new path as a child of another path.
Params:
  • parent – the parent path
  • child – the child, must not contain the file separator
/** * Creates a new path as a child of another path. * * @param parent the parent path * @param child the child, must not contain the file separator */
public TokenizedPath(TokenizedPath parent, String child) { if (!parent.path.isEmpty() && parent.path.charAt(parent.path.length() - 1) != File.separatorChar) { path = parent.path + File.separatorChar + child; } else { path = parent.path + child; } tokenizedPath = new String[parent.tokenizedPath.length + 1]; System.arraycopy(parent.tokenizedPath, 0, tokenizedPath, 0, parent.tokenizedPath.length); tokenizedPath[parent.tokenizedPath.length] = child; } /* package */ TokenizedPath(String path, String[] tokens) { this.path = path; this.tokenizedPath = tokens; }
Returns:The original path String
/** * @return The original path String */
@Override public String toString() { return path; }
The depth (or length) of a path.
Returns:int
/** * The depth (or length) of a path. * @return int */
public int depth() { return tokenizedPath.length; } /* package */ String[] getTokens() { return tokenizedPath; }
From base traverse the filesystem in order to find a file that matches the given name.
Params:
  • base – base File (dir).
  • cs – whether to scan case-sensitively.
Returns:File object that points to the file in question or null.
/** * From <code>base</code> traverse the filesystem in order to find * a file that matches the given name. * * @param base base File (dir). * @param cs whether to scan case-sensitively. * @return File object that points to the file in question or null. */
public File findFile(File base, final boolean cs) { String[] tokens = tokenizedPath; if (FileUtils.isAbsolutePath(path)) { if (base == null) { String[] s = FILE_UTILS.dissect(path); base = new File(s[0]); tokens = SelectorUtils.tokenizePathAsArray(s[1]); } else { File f = FILE_UTILS.normalize(path); String s = FILE_UTILS.removeLeadingPath(base, f); if (s.equals(f.getAbsolutePath())) { //removing base from path yields no change; path //not child of base return null; } tokens = SelectorUtils.tokenizePathAsArray(s); } } return findFile(base, tokens, cs); }
Do we have to traverse a symlink when trying to reach path from basedir?
Params:
  • base – base File (dir).
Returns:boolean
/** * Do we have to traverse a symlink when trying to reach path from * basedir? * @param base base File (dir). * @return boolean */
public boolean isSymlink(File base) { for (String token : tokenizedPath) { final Path pathToTraverse; if (base == null) { pathToTraverse = Paths.get(token); } else { pathToTraverse = Paths.get(base.toPath().toString(), token); } if (Files.isSymbolicLink(pathToTraverse)) { return true; } base = new File(base, token); } return false; }
true if the original paths are equal.
Returns:boolean
/** * true if the original paths are equal. * @return boolean */
@Override public boolean equals(Object o) { return o instanceof TokenizedPath && path.equals(((TokenizedPath) o).path); } @Override public int hashCode() { return path.hashCode(); }
From base traverse the filesystem in order to find a file that matches the given stack of names.
Params:
  • base – base File (dir) - must not be null.
  • pathElements – array of path elements (dirs...file).
  • cs – whether to scan case-sensitively.
Returns:File object that points to the file in question or null.
/** * From <code>base</code> traverse the filesystem in order to find * a file that matches the given stack of names. * * @param base base File (dir) - must not be null. * @param pathElements array of path elements (dirs...file). * @param cs whether to scan case-sensitively. * @return File object that points to the file in question or null. */
private static File findFile(File base, final String[] pathElements, final boolean cs) { for (String pathElement : pathElements) { if (!base.isDirectory()) { return null; } String[] files = base.list(); if (files == null) { throw new BuildException("IO error scanning directory %s", base.getAbsolutePath()); } boolean found = false; boolean[] matchCase = cs ? CS_SCAN_ONLY : CS_THEN_NON_CS; for (int i = 0; !found && i < matchCase.length; i++) { for (int j = 0; !found && j < files.length; j++) { if (matchCase[i] ? files[j].equals(pathElement) : files[j].equalsIgnoreCase(pathElement)) { base = new File(base, files[j]); found = true; } } } if (!found) { return null; } } return pathElements.length == 0 && !base.isDirectory() ? null : base; }
Creates a TokenizedPattern from the same tokens that make up this path.
Returns:TokenizedPattern
/** * Creates a TokenizedPattern from the same tokens that make up * this path. * * @return TokenizedPattern */
public TokenizedPattern toPattern() { return new TokenizedPattern(path, tokenizedPath); } }