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

com.github.protobufel.common.files.ContextPathMatchers Maven / Gradle / Ivy

The newest version!
/*
 * BSD 3-Clause License
 *
 * Copyright (c) 2017, David Tesler
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 *  Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

package com.github.protobufel.common.files;

import com.github.protobufel.common.files.PathContexts.PathContext;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.github.protobufel.common.verifications.Verifications.*;

public final class ContextPathMatchers {
  private ContextPathMatchers() {}

  public static  HierarchicalMatcher getHierarchicalMatcher(
      final String syntaxAndPattern,
      final boolean isUnix,
      final boolean allowDirs,
      final boolean allowFiles,
      final Class pathType) {
    final String[] parts = verifyNonNull(syntaxAndPattern).split(":", 2);
    final @NonNull String regex = verifyArgument(parts.length == 2, parts[1]);

    if (parts[0].equals("regex")) {
      return new SimpleHierarchicalMatcher(isUnix, regex, allowDirs, allowFiles);
    } else if (parts[0].equals("glob")) {
      return new SimpleHierarchicalMatcher(regex, isUnix, allowDirs, allowFiles);
    } else {
      throw new UnsupportedOperationException(String.format("%s syntax", parts[0]));
    }
  }

  interface HierarchicalMatcherCommon {
    boolean isEmpty();

    boolean isAllowDirs();

    boolean isAllowFiles();

    String getPattern();
  }

  public interface ContextHierarchicalMatcher extends HierarchicalMatcherCommon {
    boolean matches(T path, PathContext pathContext);

    DirectoryMatchResult matchesDirectory(T path, PathContext pathContext);
  }

  public interface BasicHierarchicalMatcher extends HierarchicalMatcherCommon {
    boolean matchesResolved(@Nullable String path, PathContext pathContext);

    DirectoryMatchResult matchesResolvedDirectory(
        @Nullable String path, @Nullable String separator, PathContext pathContext);
  }

  public interface HierarchicalMatcher
      extends ContextHierarchicalMatcher, BasicHierarchicalMatcher {}

  public static final class SimpleHierarchicalMatcher implements HierarchicalMatcher {
    @SuppressWarnings("null")
    private static final Pattern UNIX_TO_WINDOWS_SLASH_FIND_REGEX =
        Pattern.compile("/|(?:(\\\\*+)(?:(\\[)|(\\])|(Q)|(E)))");
    private final Pattern pattern;
    private final boolean allowDirs;
    private final boolean allowFiles;
    private final boolean isUnix;

    public SimpleHierarchicalMatcher(final SimpleHierarchicalMatcher other) {
      this.pattern = other.pattern;
      this.allowDirs = other.allowDirs;
      this.allowFiles = other.allowFiles;
      this.isUnix = other.isUnix;
    }

    public SimpleHierarchicalMatcher(
        final String glob,
        final boolean isUnix,
        final boolean allowDirs,
        final boolean allowFiles) {
      this(isUnix, convertGlobToRegex(glob, isUnix), true, allowDirs, allowFiles);
    }

    public SimpleHierarchicalMatcher(
        final boolean isUnix,
        final String regex,
        final boolean allowDirs,
        final boolean allowFiles) {
      this(isUnix, regex, false, allowDirs, allowFiles);
    }

    public SimpleHierarchicalMatcher(
        final boolean isUnix,
        final String regex,
        final boolean isRegexSystemSpecific,
        final boolean allowDirs,
        final boolean allowFiles) {
      verifyCondition((allowDirs || allowFiles), "allowDirs and allowFiles cannot be both false");
      this.allowDirs = allowDirs;
      this.allowFiles = allowFiles;
      final String regexFlags = isUnix ? "" : "(?iu)";
      final String fsRegex =
          isRegexSystemSpecific ? regex : convertRegexToSystemSpecific(regex, isUnix);
      @SuppressWarnings("null")
      @NonNull
      Pattern compiled = Pattern.compile(regexFlags + verifyNonNull(fsRegex));
      this.pattern = compiled;
      this.isUnix = isUnix;
    }

    protected static final String convertGlobToRegex(final String glob, final boolean isUnix) {
      if (isUnix) {
        return Globs.toUnixRegexPattern(glob);
      } else {
        return Globs.toWindowsRegexPattern(glob);
      }
    }

    @SuppressWarnings("null")
    @Override
    public String getPattern() {
      return pattern.pattern();
    }

    @Override
    public String toString() {
      return "SimpleHierarchicalMatcher [pattern="
          + pattern
          + ", flags="
          + pattern.flags()
          + ", allowDirs="
          + allowDirs
          + ", allowFiles="
          + allowFiles
          + ", isUnix="
          + isUnix
          + "]";
    }

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + (allowDirs ? 1231 : 1237);
      result = prime * result + (allowFiles ? 1231 : 1237);
      result = prime * result + (isUnix ? 1231 : 1237);
      result = prime * result + pattern.pattern().hashCode();
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) {
        return true;
      }
      if (obj == null) {
        return false;
      }
      if (!(obj instanceof SimpleHierarchicalMatcher)) {
        return false;
      }
      final SimpleHierarchicalMatcher other = (SimpleHierarchicalMatcher) obj;
      if (allowDirs != other.allowDirs) {
        return false;
      }
      if (allowFiles != other.allowFiles) {
        return false;
      }
      if (isUnix != other.isUnix) {
        return false;
      }
      if (!pattern.pattern().equals(other.pattern.pattern())) {
        return false;
      }
      return true;
    }

    @Override
    public boolean isEmpty() {
      return "".equals(pattern.pattern());
    }

    public boolean isAllowDirs() {
      return allowDirs;
    }

    public boolean isAllowFiles() {
      return allowFiles;
    }

    @Override
    public boolean matches(final T path, final PathContext pathContext) {
      return matchesResolved(pathContext.resolvePath(path), pathContext);
    }

    @Override
    public DirectoryMatchResult matchesDirectory(final T path, final PathContext pathContext) {
      return matchesResolvedDirectory(
          pathContext.resolvePath(path), pathContext.getSeparator(path), pathContext);
    }

    @Override
    public boolean matchesResolved(final @Nullable String path, final PathContext pathContext) {
      return (allowFiles && (path != null)) ? pattern.matcher(path).matches() : false;
    }

    @Override
    public DirectoryMatchResult matchesResolvedDirectory(
        final @Nullable String path,
        final @Nullable String separator,
        final PathContext pathContext) {
      if ((path == null) || (separator == null)) {
        return DirectoryMatchResult.NO_MATCH;
      }

      final String pathWithSlash = path + separator;
      final Matcher matcher;
      final boolean isMatched;

      if (allowDirs) {
        matcher = pattern.matcher(path);
        isMatched = matcher.matches();
        matcher.reset(pathWithSlash);
      } else {
        matcher = pattern.matcher(pathWithSlash);
        isMatched = false;
      }

      final boolean skip = matcher.matches() ? matcher.requireEnd() : (!matcher.hitEnd());
      return DirectoryMatchResult.valueOf(isMatched, skip);
    }

    protected final String convertRegexToSystemSpecific(
        final String normalizedRelativeRegex, final boolean isUnix) {
      if (isUnix) {
        return normalizedRelativeRegex;
      } else {
        return convertNormalizedRelativeRegexToWindows(normalizedRelativeRegex);
      }
    }

    protected final String convertNormalizedRelativeRegexToWindows(
        final String normalizedRelativeRegex) {
      @SuppressWarnings("null")
      final @NonNull Matcher matcher =
          UNIX_TO_WINDOWS_SLASH_FIND_REGEX.matcher(normalizedRelativeRegex);
      final StringBuffer sb = new StringBuffer();
      boolean foundCharGroup = false;
      boolean foundQuote = false;

      while (matcher.find()) {
        if (foundQuote) {
          if (matcher.group(5) != null) {
            if ((matcher.group(1).length() % 2) == 1) {
              foundQuote = false;
            }
          }
        } else if (matcher.group(4) != null) {
          if ((matcher.group(1).length() % 2) == 1) {
            foundQuote = true;
          }
        } else if (matcher.group(2) != null) {
          if ((matcher.group(1).length() % 2) == 0) {
            foundCharGroup = true;
          }
        } else if (matcher.group(3) != null) {
          if ((matcher.group(1).length() % 2) == 0) {
            foundCharGroup = false;
          }
        } else if (!foundCharGroup) {
          matcher.appendReplacement(sb, "\\\\\\\\");
        }
      }

      @SuppressWarnings("null")
      final @NonNull String result = matcher.appendTail(sb).toString();
      return result;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy