NameMatcher.java

  1. /*
  2.  * Copyright (C) 2014, Andrey Loskutov <loskutov@gmx.de> and others
  3.  *
  4.  * This program and the accompanying materials are made available under the
  5.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  6.  * https://www.eclipse.org/org/documents/edl-v10.php.
  7.  *
  8.  * SPDX-License-Identifier: BSD-3-Clause
  9.  */
  10. package org.eclipse.jgit.ignore.internal;

  11. import static org.eclipse.jgit.ignore.internal.Strings.getPathSeparator;

  12. /**
  13.  * Matcher built from patterns for file names (single path segments). This class
  14.  * is immutable and thread safe.
  15.  */
  16. public class NameMatcher extends AbstractMatcher {

  17.     final boolean beginning;

  18.     final char slash;

  19.     final String subPattern;

  20.     NameMatcher(String pattern, Character pathSeparator, boolean dirOnly,
  21.             boolean deleteBackslash) {
  22.         super(pattern, dirOnly);
  23.         slash = getPathSeparator(pathSeparator);
  24.         if (deleteBackslash) {
  25.             pattern = Strings.deleteBackslash(pattern);
  26.         }
  27.         beginning = pattern.length() == 0 ? false : pattern.charAt(0) == slash;
  28.         if (!beginning) {
  29.             this.subPattern = pattern;
  30.         } else {
  31.             this.subPattern = pattern.substring(1);
  32.         }
  33.     }

  34.     /** {@inheritDoc} */
  35.     @Override
  36.     public boolean matches(String path, boolean assumeDirectory,
  37.             boolean pathMatch) {
  38.         // A NameMatcher's pattern does not contain a slash.
  39.         int start = 0;
  40.         int stop = path.length();
  41.         if (stop > 0 && path.charAt(0) == slash) {
  42.             start++;
  43.         }
  44.         if (pathMatch) {
  45.             // Can match only after the last slash
  46.             int lastSlash = path.lastIndexOf(slash, stop - 1);
  47.             if (lastSlash == stop - 1) {
  48.                 // Skip trailing slash
  49.                 lastSlash = path.lastIndexOf(slash, lastSlash - 1);
  50.                 stop--;
  51.             }
  52.             boolean match;
  53.             if (lastSlash < start) {
  54.                 match = matches(path, start, stop);
  55.             } else {
  56.                 // Can't match if the path contains a slash if the pattern is
  57.                 // anchored at the beginning
  58.                 match = !beginning
  59.                         && matches(path, lastSlash + 1, stop);
  60.             }
  61.             if (match && dirOnly) {
  62.                 match = assumeDirectory;
  63.             }
  64.             return match;
  65.         }
  66.         while (start < stop) {
  67.             int end = path.indexOf(slash, start);
  68.             if (end < 0) {
  69.                 end = stop;
  70.             }
  71.             if (end > start && matches(path, start, end)) {
  72.                 // make sure the directory matches: either if we are done with
  73.                 // segment and there is next one, or if the directory is assumed
  74.                 return !dirOnly || assumeDirectory || end < stop;
  75.             }
  76.             if (beginning) {
  77.                 break;
  78.             }
  79.             start = end + 1;
  80.         }
  81.         return false;
  82.     }

  83.     /** {@inheritDoc} */
  84.     @Override
  85.     public boolean matches(String segment, int startIncl, int endExcl) {
  86.         // faster local access, same as in string.indexOf()
  87.         String s = subPattern;
  88.         int length = s.length();
  89.         if (length != (endExcl - startIncl)) {
  90.             return false;
  91.         }
  92.         for (int i = 0; i < length; i++) {
  93.             char c1 = s.charAt(i);
  94.             char c2 = segment.charAt(i + startIncl);
  95.             if (c1 != c2) {
  96.                 return false;
  97.             }
  98.         }
  99.         return true;
  100.     }

  101. }