All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xmlbeans.impl.jam.internal.DirectoryScanner Maven / Gradle / Ivy

Go to download

The Apache Commons Codec package contains simple encoder and decoders for various formats such as Base64 and Hexadecimal. In addition to these widely used encoders and decoders, the codec package also maintains a collection of phonetic encoding utilities.

The newest version!
/*   Copyright 2004 The Apache Software Foundation
 *
 *   Licensed 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
 *
 *       http://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.xmlbeans.impl.jam.internal;

import org.apache.xmlbeans.impl.jam.provider.JamLogger;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;

/**
 *
 * @author Patrick Calahan <email: pcal-at-bea-dot-com>
 */
public class DirectoryScanner {

  // ========================================================================
  // Variables

  private boolean mCaseSensitive = true;
  private File mRoot;
  private JamLogger mLogger;
  private List mIncludeList = null;
  private List mExcludeList = null;
  private String[] mIncludes;
  private String[] mExcludes;
  private Vector mFilesIncluded;
  private Vector mDirsIncluded;
  private boolean mIsDirty = false;
  private String[] mIncludedFilesCache = null;


  // ========================================================================
  // Constructors

  public DirectoryScanner(File dirToScan, JamLogger logger) {
    if (logger == null) throw new IllegalArgumentException("null logger");
    mLogger = logger;
    mRoot = dirToScan;
  }

  // ========================================================================
  // Public methods

  public void include(String pattern) {
    if (mIncludeList == null) mIncludeList = new ArrayList();
    mIncludeList.add(pattern);
    mIsDirty = true;
  }

  public void exclude(String pattern) {
    if (mExcludeList == null) mExcludeList = new ArrayList();
    mExcludeList.add(pattern);
    mIsDirty = true;
  }

  /**
   * Scans the root directory with the patterns that have been included
   * and excluded and returns the names of the resulting file set
   * relative to the root dir.
   */
  public String[] getIncludedFiles() throws IOException {
    if (!mIsDirty && mIncludedFilesCache != null) {
      return mIncludedFilesCache;
    }
    if (mIncludeList != null) {
      String[] inc = new String[mIncludeList.size()];
      mIncludeList.toArray(inc);
      setIncludes(inc);
    } else {
      setIncludes(null);
    }
    if (mExcludeList != null) {
      String[] exc = new String[mExcludeList.size()];
      mExcludeList.toArray(exc);
      setExcludes(exc);
    } else {
      setExcludes(null);
    }
    scan();
    mIncludedFilesCache = new String[mFilesIncluded.size()];
    mFilesIncluded.copyInto(mIncludedFilesCache);
    return mIncludedFilesCache;
  }

  public void setDirty() {
    mIsDirty = true;
  }

  public File getRoot() {
    return mRoot;
  }

  // ========================================================================
  // Private methods

  /**
   * Sets the list of include patterns to use. All '/' and '\' characters
   * are replaced by File.separatorChar, so the separator used
   * need not match File.separatorChar.
   * 

* When a pattern ends with a '/' or '\', "**" is appended. * * @param includes A list of include patterns. * May be null, indicating that all files * should be included. If a non-null * list is given, all elements2 must be * non-null. */ private void setIncludes(String[] includes) { if (includes == null) { this.mIncludes = null; } else { this.mIncludes = new String[includes.length]; for (int i = 0; i < includes.length; i++) { String pattern; pattern = includes[i].replace('/', File.separatorChar). replace('\\', File.separatorChar); if (pattern.endsWith(File.separator)) { pattern += "**"; } this.mIncludes[i] = pattern; } } } /** * Sets the list of exclude patterns to use. All '/' and '\' characters * are replaced by File.separatorChar, so the separator used * need not match File.separatorChar. *

* When a pattern ends with a '/' or '\', "**" is appended. * * @param excludes A list of exclude patterns. * May be null, indicating that no files * should be excluded. If a non-null list is * given, all elements2 must be non-null. */ private void setExcludes(String[] excludes) { if (excludes == null) { this.mExcludes = null; } else { this.mExcludes = new String[excludes.length]; for (int i = 0; i < excludes.length; i++) { String pattern; pattern = excludes[i].replace('/', File.separatorChar). replace('\\', File.separatorChar); if (pattern.endsWith(File.separator)) { pattern += "**"; } this.mExcludes[i] = pattern; } } } /** * Scans the base directory for files which match at least one * include pattern and don't match any exclude patterns. If there * are selectors then the files must pass muster there, as well. * * @exception IllegalStateException if the base directory was set * incorrectly (i.e. if it is null, doesn't exist, * or isn't a directory). */ private void scan() throws IllegalStateException, IOException { if (mIncludes == null) { // No mIncludes supplied, so set it to 'matches all' mIncludes = new String[1]; mIncludes[0] = "**"; } if (mExcludes == null) { mExcludes = new String[0]; } mFilesIncluded = new Vector(); mDirsIncluded = new Vector(); if (isIncluded("")) { if (!isExcluded("")) { mDirsIncluded.addElement(""); } } scandir(mRoot, "", true); } /** * Scans the given directory for files and directories. Found files and * directories are placed in their respective collections, based on the * matching of mIncludes, mExcludes, and the selectors. When a directory * is found, it is scanned recursively. * * @param dir The directory to scan. Must not be null. * @param vpath The path relative to the base directory (needed to * prevent problems with an absolute path when using * dir). Must not be null. * @param fast Whether or not this call is part of a fast scan. * * @see #mFilesIncluded * @see #mDirsIncluded */ private void scandir(File dir, String vpath, boolean fast) throws IOException { if (mLogger.isVerbose(this)) { mLogger.verbose("[DirectoryScanner] scanning dir "+dir+" for '"+vpath+"'"); } String[] newfiles = dir.list(); if (newfiles == null) { /* * two reasons are mentioned in the API docs for File.list * (1) dir is not a directory. This is impossible as * we wouldn't get here in this case. * (2) an IO error occurred (why doesn't it throw an exception * then???) */ throw new IOException("IO error scanning directory " + dir.getAbsolutePath()); } /* if (!followSymlinks) { Vector noLinks = new Vector(); for (int i = 0; i < newfiles.length; i++) { try { if (fileUtils.isSymbolicLink(dir, newfiles[i])) { String name = vpath + newfiles[i]; File file = new File(dir, newfiles[i]); if (file.isDirectory()) { dirsExcluded.addElement(name); } else { filesExcluded.addElement(name); } } else { noLinks.addElement(newfiles[i]); } } catch (IOException ioe) { String msg = "IOException caught while checking " + "for links, couldn't get cannonical path!"; // will be caught and redirected to Ant's logging system System.err.println(msg); noLinks.addElement(newfiles[i]); } } newfiles = new String[noLinks.size()]; noLinks.copyInto(newfiles); }*/ for (int i = 0; i < newfiles.length; i++) { String name = vpath + newfiles[i]; File file = new File(dir, newfiles[i]); if (file.isDirectory()) { if (isIncluded(name) && !isExcluded(name)) { mDirsIncluded.addElement(name); if (mLogger.isVerbose(this)) mLogger.verbose("...including dir "+name); scandir(file, name + File.separator, fast); } else { if (couldHoldIncluded(name)) { scandir(file, name + File.separator, fast); } } } else if (file.isFile()) { if (isIncluded(name)) { if (!isExcluded(name)) { mFilesIncluded.addElement(name); if (mLogger.isVerbose(this)) { mLogger.verbose("...including "+name+" under '"+dir); } } else { if (mLogger.isVerbose(this)) { mLogger.verbose("...EXCLUDING "+name+" under '"+dir); } } } } } } /** * Tests whether or not a name matches against at least one include * pattern. * * @param name The name to match. Must not be null. * @return true when the name matches against at least one * include pattern, or false otherwise. */ private boolean isIncluded(String name) { for (int i = 0; i < mIncludes.length; i++) { if (matchPath(mIncludes[i], name, mCaseSensitive)) { return true; } } return false; } /** * Tests whether or not a name matches the start of at least one include * pattern. * * @param name The name to match. Must not be null. * @return true when the name matches against the start of at * least one include pattern, or false otherwise. */ private boolean couldHoldIncluded(String name) { for (int i = 0; i < mIncludes.length; i++) { if (matchPatternStart(mIncludes[i], name, mCaseSensitive)) { return true; } } return false; } /** * Tests whether or not a name matches against at least one exclude * pattern. * * @param name The name to match. Must not be null. * @return true when the name matches against at least one * exclude pattern, or false otherwise. */ private boolean isExcluded(String name) { for (int i = 0; i < mExcludes.length; i++) { if (matchPath(mExcludes[i], name, mCaseSensitive)) { return true; } } return false; } /** * Returns the names of the directories which matched at least one * of the include patterns and none of the exclude patterns. The * names are relative to the base directory. * * @return the names of the directories which matched at least one of the * include patterns and none of the exclude patterns. private String[] getIncludedDirectories() { String[] directories = new String[mDirsIncluded.size()]; mDirsIncluded.copyInto(directories); return directories; } */ // ======================================================================== // SelectorUtils stuff /** * Tests whether or not a given path matches the start of a given * pattern up to the first "**". *

* This is not a general purpose test and should only be used if you * can live with false positives. For example, pattern=**\a * and str=b will yield true. * * @param pattern The pattern to match against. Must not be * null. * @param str The path to match, as a String. Must not be * null. * * @return whether or not a given path matches the start of a given * pattern up to the first "**". private static boolean matchPatternStart(String pattern, String str) { return matchPatternStart(pattern, str, true); } */ /** * Tests whether or not a given path matches the start of a given * pattern up to the first "**". *

* This is not a general purpose test and should only be used if you * can live with false positives. For example, pattern=**\a * and str=b will yield true. * * @param pattern The pattern to match against. Must not be * null. * @param str The path to match, as a String. Must not be * null. * @param mCaseSensitive Whether or not matching should be performed * case sensitively. * * @return whether or not a given path matches the start of a given * pattern up to the first "**". */ private static boolean matchPatternStart(String pattern, String str, boolean mCaseSensitive) { // When str starts with a File.separator, pattern has to start with a // File.separator. // When pattern starts with a File.separator, str has to start with a // File.separator. if (str.startsWith(File.separator) != pattern.startsWith(File.separator)) { return false; } Vector patDirs = tokenizePath(pattern); Vector strDirs = tokenizePath(str); int patIdxStart = 0; int patIdxEnd = patDirs.size() - 1; int strIdxStart = 0; int strIdxEnd = strDirs.size() - 1; // up to first '**' while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { String patDir = (String) patDirs.elementAt(patIdxStart); if (patDir.equals("**")) { break; } if (!match(patDir, (String) strDirs.elementAt(strIdxStart), mCaseSensitive)) { return false; } patIdxStart++; strIdxStart++; } if (strIdxStart > strIdxEnd) { // String is exhausted return true; } else if (patIdxStart > patIdxEnd) { // String not exhausted, but pattern is. Failure. return false; } else { // pattern now holds ** while string is not exhausted // this will generate false positives but we can live with that. return true; } } /** * Tests whether or not a given path matches a given pattern. * * @param pattern The pattern to match against. Must not be * null. * @param str The path to match, as a String. Must not be * null. * * @return true if the pattern matches against the string, * or false otherwise. private static boolean matchPath(String pattern, String str) { return matchPath(pattern, str, true); } */ /** * Tests whether or not a given path matches a given pattern. * * @param pattern The pattern to match against. Must not be * null. * @param str The path to match, as a String. Must not be * null. * @param mCaseSensitive Whether or not matching should be performed * case sensitively. * * @return true if the pattern matches against the string, * or false otherwise. */ private static boolean matchPath(String pattern, String str, boolean mCaseSensitive) { // When str starts with a File.separator, pattern has to start with a // File.separator. // When pattern starts with a File.separator, str has to start with a // File.separator. if (str.startsWith(File.separator) != pattern.startsWith(File.separator)) { return false; } Vector patDirs = tokenizePath(pattern); Vector strDirs = tokenizePath(str); int patIdxStart = 0; int patIdxEnd = patDirs.size() - 1; int strIdxStart = 0; int strIdxEnd = strDirs.size() - 1; // up to first '**' while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { String patDir = (String) patDirs.elementAt(patIdxStart); if (patDir.equals("**")) { break; } if (!match(patDir, (String) strDirs.elementAt(strIdxStart), mCaseSensitive)) { return false; } patIdxStart++; strIdxStart++; } if (strIdxStart > strIdxEnd) { // String is exhausted for (int i = patIdxStart; i <= patIdxEnd; i++) { if (!patDirs.elementAt(i).equals("**")) { return false; } } return true; } else { if (patIdxStart > patIdxEnd) { // String not exhausted, but pattern is. Failure. return false; } } // up to last '**' while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { String patDir = (String) patDirs.elementAt(patIdxEnd); if (patDir.equals("**")) { break; } if (!match(patDir, (String) strDirs.elementAt(strIdxEnd), mCaseSensitive)) { return false; } patIdxEnd--; strIdxEnd--; } if (strIdxStart > strIdxEnd) { // String is exhausted for (int i = patIdxStart; i <= patIdxEnd; i++) { if (!patDirs.elementAt(i).equals("**")) { return false; } } return true; } while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { int patIdxTmp = -1; for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { if (patDirs.elementAt(i).equals("**")) { patIdxTmp = i; break; } } if (patIdxTmp == patIdxStart + 1) { // '**/**' situation, so skip one patIdxStart++; continue; } // Find the pattern between padIdxStart & padIdxTmp in str between // strIdxStart & strIdxEnd int patLength = (patIdxTmp - patIdxStart - 1); int strLength = (strIdxEnd - strIdxStart + 1); int foundIdx = -1; strLoop: for (int i = 0; i <= strLength - patLength; i++) { for (int j = 0; j < patLength; j++) { String subPat = (String) patDirs.elementAt(patIdxStart + j + 1); String subStr = (String) strDirs.elementAt(strIdxStart + i + j); if (!match(subPat, subStr, mCaseSensitive)) { continue strLoop; } } foundIdx = strIdxStart + i; break; } if (foundIdx == -1) { return false; } patIdxStart = patIdxTmp; strIdxStart = foundIdx + patLength; } for (int i = patIdxStart; i <= patIdxEnd; i++) { if (!patDirs.elementAt(i).equals("**")) { return false; } } return true; } /** * Tests whether or not a string matches against a pattern. The * pattern may contain two special characters:
'*' means zero or * more characters
'?' means one and only one character * * @param pattern The pattern to match against. * Must not be null. * @param str The string which must be matched against the pattern. * Must not be null. * @param mCaseSensitive Whether or not matching should be performed * case sensitively. * * * @return true if the string matches against the pattern, * or false otherwise. */ private static boolean match(String pattern, String str, boolean mCaseSensitive) { char[] patArr = pattern.toCharArray(); char[] strArr = str.toCharArray(); int patIdxStart = 0; int patIdxEnd = patArr.length - 1; int strIdxStart = 0; int strIdxEnd = strArr.length - 1; char ch; boolean containsStar = false; for (int i = 0; i < patArr.length; i++) { if (patArr[i] == '*') { containsStar = true; break; } } if (!containsStar) { // No '*'s, so we make a shortcut if (patIdxEnd != strIdxEnd) { return false; // Pattern and string do not have the same size } for (int i = 0; i <= patIdxEnd; i++) { ch = patArr[i]; if (ch != '?') { if (mCaseSensitive && ch != strArr[i]) { return false;// Character mismatch } if (!mCaseSensitive && Character.toUpperCase(ch) != Character.toUpperCase(strArr[i])) { return false; // Character mismatch } } } return true; // String matches against pattern } if (patIdxEnd == 0) { return true; // Pattern contains only '*', which matches anything } // Process characters before first star while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) { if (ch != '?') { if (mCaseSensitive && ch != strArr[strIdxStart]) { return false;// Character mismatch } if (!mCaseSensitive && Character.toUpperCase(ch) != Character.toUpperCase(strArr[strIdxStart])) { return false;// Character mismatch } } patIdxStart++; strIdxStart++; } if (strIdxStart > strIdxEnd) { // All characters in the string are used. Check if only '*'s are // left in the pattern. If so, we succeeded. Otherwise failure. for (int i = patIdxStart; i <= patIdxEnd; i++) { if (patArr[i] != '*') { return false; } } return true; } // Process characters after last star while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) { if (ch != '?') { if (mCaseSensitive && ch != strArr[strIdxEnd]) { return false;// Character mismatch } if (!mCaseSensitive && Character.toUpperCase(ch) != Character.toUpperCase(strArr[strIdxEnd])) { return false;// Character mismatch } } patIdxEnd--; strIdxEnd--; } if (strIdxStart > strIdxEnd) { // All characters in the string are used. Check if only '*'s are // left in the pattern. If so, we succeeded. Otherwise failure. for (int i = patIdxStart; i <= patIdxEnd; i++) { if (patArr[i] != '*') { return false; } } return true; } // process pattern between stars. padIdxStart and patIdxEnd point // always to a '*'. while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { int patIdxTmp = -1; for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { if (patArr[i] == '*') { patIdxTmp = i; break; } } if (patIdxTmp == patIdxStart + 1) { // Two stars next to each other, skip the first one. patIdxStart++; continue; } // Find the pattern between padIdxStart & padIdxTmp in str between // strIdxStart & strIdxEnd int patLength = (patIdxTmp - patIdxStart - 1); int strLength = (strIdxEnd - strIdxStart + 1); int foundIdx = -1; strLoop: for (int i = 0; i <= strLength - patLength; i++) { for (int j = 0; j < patLength; j++) { ch = patArr[patIdxStart + j + 1]; if (ch != '?') { if (mCaseSensitive && ch != strArr[strIdxStart + i + j]) { continue strLoop; } if (!mCaseSensitive && Character.toUpperCase(ch) != Character.toUpperCase(strArr[strIdxStart + i + j])) { continue strLoop; } } } foundIdx = strIdxStart + i; break; } if (foundIdx == -1) { return false; } patIdxStart = patIdxTmp; strIdxStart = foundIdx + patLength; } // All characters in the string are used. Check if only '*'s are left // in the pattern. If so, we succeeded. Otherwise failure. for (int i = patIdxStart; i <= patIdxEnd; i++) { if (patArr[i] != '*') { return false; } } return true; } /** * Breaks a path up into a Vector of path elements2, tokenizing on * File.separator. * * @param path Path to tokenize. Must not be null. * * @return a Vector of path elements2 from the tokenized path */ private static Vector tokenizePath(String path) { Vector ret = new Vector(); StringTokenizer st = new StringTokenizer(path, File.separator); while (st.hasMoreTokens()) { ret.addElement(st.nextToken()); } return ret; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy