blob: 7f6198fa45f16db7e51888117151c7fcd2ea05d2 [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../../jacoco-resources/report.gif" type="image/gif"/><title>AntPathMatcher.java</title><link rel="stylesheet" href="../../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../../index.html" class="el_report">Apache Shiro :: Test Coverage</a> &gt; <a href="../index.html" class="el_bundle">shiro-core</a> &gt; <a href="index.source.html" class="el_package">org.apache.shiro.util</a> &gt; <span class="el_source">AntPathMatcher.java</span></div><h1>AntPathMatcher.java</h1><pre class="source lang-java linenums">/*
* 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
* &quot;License&quot;); 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
* &quot;AS IS&quot; 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.shiro.util;
/**
* &lt;p&gt;PathMatcher implementation for Ant-style path patterns.
* Examples are provided below.&lt;/p&gt;
*
* &lt;p&gt;Part of this mapping code has been kindly borrowed from
* &lt;a href=&quot;http://ant.apache.org&quot;&gt;Apache Ant&lt;/a&gt;.
*
* &lt;p&gt;The mapping matches URLs using the following rules:&lt;br&gt;
* &lt;ul&gt;
* &lt;li&gt;? matches one character&lt;/li&gt;
* &lt;li&gt;* matches zero or more characters&lt;/li&gt;
* &lt;li&gt;** matches zero or more 'directories' in a path&lt;/li&gt;
* &lt;/ul&gt;
*
* &lt;p&gt;Some examples:&lt;br&gt;
* &lt;ul&gt;
* &lt;li&gt;&lt;code&gt;com/t?st.jsp&lt;/code&gt; - matches &lt;code&gt;com/test.jsp&lt;/code&gt; but also
* &lt;code&gt;com/tast.jsp&lt;/code&gt; or &lt;code&gt;com/txst.jsp&lt;/code&gt;&lt;/li&gt;
* &lt;li&gt;&lt;code&gt;com/*.jsp&lt;/code&gt; - matches all &lt;code&gt;.jsp&lt;/code&gt; files in the
* &lt;code&gt;com&lt;/code&gt; directory&lt;/li&gt;
* &lt;li&gt;&lt;code&gt;com/&amp;#42;&amp;#42;/test.jsp&lt;/code&gt; - matches all &lt;code&gt;test.jsp&lt;/code&gt;
* files underneath the &lt;code&gt;com&lt;/code&gt; path&lt;/li&gt;
* &lt;li&gt;&lt;code&gt;org/apache/shiro/&amp;#42;&amp;#42;/*.jsp&lt;/code&gt; - matches all &lt;code&gt;.jsp&lt;/code&gt;
* files underneath the &lt;code&gt;org/apache/shiro&lt;/code&gt; path&lt;/li&gt;
* &lt;li&gt;&lt;code&gt;org/&amp;#42;&amp;#42;/servlet/bla.jsp&lt;/code&gt; - matches
* &lt;code&gt;org/apache/shiro/servlet/bla.jsp&lt;/code&gt; but also
* &lt;code&gt;org/apache/shiro/testing/servlet/bla.jsp&lt;/code&gt; and
* &lt;code&gt;org/servlet/bla.jsp&lt;/code&gt;&lt;/li&gt;
* &lt;/ul&gt;
*
* &lt;p&gt;&lt;b&gt;N.B.&lt;/b&gt;: This class was borrowed (with much appreciation) from the
* &lt;a href=&quot;http://www.springframework.org&quot;&gt;Spring Framework&lt;/a&gt; with modifications. We didn't want to reinvent the
* wheel of great work they've done, but also didn't want to force every Shiro user to depend on Spring&lt;/p&gt;
*
* &lt;p&gt;As per the Apache 2.0 license, the original copyright notice and all author and copyright information have
* remained in tact.&lt;/p&gt;
*
* @since 16.07.2003
*/
<span class="fc" id="L60">public class AntPathMatcher implements PatternMatcher {</span>
//TODO - complete JavaDoc
/**
* Default path separator: &quot;/&quot;
*/
public static final String DEFAULT_PATH_SEPARATOR = &quot;/&quot;;
<span class="fc" id="L69"> private String pathSeparator = DEFAULT_PATH_SEPARATOR;</span>
/**
* Set the path separator to use for pattern parsing.
* Default is &quot;/&quot;, as in Ant.
*/
public void setPathSeparator(String pathSeparator) {
<span class="nc bnc" id="L77" title="All 2 branches missed."> this.pathSeparator = (pathSeparator != null ? pathSeparator : DEFAULT_PATH_SEPARATOR);</span>
<span class="nc" id="L78"> }</span>
public boolean isPattern(String path) {
<span class="nc bnc" id="L82" title="All 4 branches missed."> return (path.indexOf('*') != -1 || path.indexOf('?') != -1);</span>
}
public boolean matches(String pattern, String source) {
<span class="fc" id="L86"> return match(pattern, source);</span>
}
public boolean match(String pattern, String path) {
<span class="fc" id="L90"> return doMatch(pattern, path, true);</span>
}
public boolean matchStart(String pattern, String path) {
<span class="nc" id="L94"> return doMatch(pattern, path, false);</span>
}
/**
* Actually match the given &lt;code&gt;path&lt;/code&gt; against the given &lt;code&gt;pattern&lt;/code&gt;.
*
* @param pattern the pattern to match against
* @param path the path String to test
* @param fullMatch whether a full pattern match is required
* (else a pattern match as far as the given base path goes is sufficient)
* @return &lt;code&gt;true&lt;/code&gt; if the supplied &lt;code&gt;path&lt;/code&gt; matched,
* &lt;code&gt;false&lt;/code&gt; if it didn't
*/
protected boolean doMatch(String pattern, String path, boolean fullMatch) {
<span class="pc bpc" id="L109" title="1 of 2 branches missed."> if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) {</span>
<span class="nc" id="L110"> return false;</span>
}
<span class="fc" id="L113"> String[] pattDirs = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator);</span>
<span class="fc" id="L114"> String[] pathDirs = StringUtils.tokenizeToStringArray(path, this.pathSeparator);</span>
<span class="fc" id="L116"> int pattIdxStart = 0;</span>
<span class="fc" id="L117"> int pattIdxEnd = pattDirs.length - 1;</span>
<span class="fc" id="L118"> int pathIdxStart = 0;</span>
<span class="fc" id="L119"> int pathIdxEnd = pathDirs.length - 1;</span>
// Match all elements up to the first **
<span class="fc bfc" id="L122" title="All 4 branches covered."> while (pattIdxStart &lt;= pattIdxEnd &amp;&amp; pathIdxStart &lt;= pathIdxEnd) {</span>
<span class="fc" id="L123"> String patDir = pattDirs[pattIdxStart];</span>
<span class="fc bfc" id="L124" title="All 2 branches covered."> if (&quot;**&quot;.equals(patDir)) {</span>
<span class="fc" id="L125"> break;</span>
}
<span class="fc bfc" id="L127" title="All 2 branches covered."> if (!matchStrings(patDir, pathDirs[pathIdxStart])) {</span>
<span class="fc" id="L128"> return false;</span>
}
<span class="fc" id="L130"> pattIdxStart++;</span>
<span class="fc" id="L131"> pathIdxStart++;</span>
<span class="fc" id="L132"> }</span>
<span class="fc bfc" id="L134" title="All 2 branches covered."> if (pathIdxStart &gt; pathIdxEnd) {</span>
// Path is exhausted, only match if rest of pattern is * or **'s
<span class="fc bfc" id="L136" title="All 2 branches covered."> if (pattIdxStart &gt; pattIdxEnd) {</span>
<span class="pc bpc" id="L137" title="1 of 2 branches missed."> return (pattern.endsWith(this.pathSeparator) ?</span>
<span class="pc bpc" id="L138" title="1 of 2 branches missed."> path.endsWith(this.pathSeparator) : !path.endsWith(this.pathSeparator));</span>
}
<span class="pc bpc" id="L140" title="1 of 2 branches missed."> if (!fullMatch) {</span>
<span class="nc" id="L141"> return true;</span>
}
<span class="pc bpc" id="L143" title="1 of 4 branches missed."> if (pattIdxStart == pattIdxEnd &amp;&amp; pattDirs[pattIdxStart].equals(&quot;*&quot;) &amp;&amp;</span>
<span class="nc bnc" id="L144" title="All 2 branches missed."> path.endsWith(this.pathSeparator)) {</span>
<span class="nc" id="L145"> return true;</span>
}
<span class="fc bfc" id="L147" title="All 2 branches covered."> for (int i = pattIdxStart; i &lt;= pattIdxEnd; i++) {</span>
<span class="fc bfc" id="L148" title="All 2 branches covered."> if (!pattDirs[i].equals(&quot;**&quot;)) {</span>
<span class="fc" id="L149"> return false;</span>
}
}
<span class="fc" id="L152"> return true;</span>
<span class="pc bpc" id="L153" title="1 of 2 branches missed."> } else if (pattIdxStart &gt; pattIdxEnd) {</span>
// String not exhausted, but pattern is. Failure.
<span class="nc" id="L155"> return false;</span>
<span class="pc bpc" id="L156" title="3 of 4 branches missed."> } else if (!fullMatch &amp;&amp; &quot;**&quot;.equals(pattDirs[pattIdxStart])) {</span>
// Path start definitely matches due to &quot;**&quot; part in pattern.
<span class="nc" id="L158"> return true;</span>
}
// up to last '**'
<span class="pc bpc" id="L162" title="2 of 4 branches missed."> while (pattIdxStart &lt;= pattIdxEnd &amp;&amp; pathIdxStart &lt;= pathIdxEnd) {</span>
<span class="fc" id="L163"> String patDir = pattDirs[pattIdxEnd];</span>
<span class="pc bpc" id="L164" title="1 of 2 branches missed."> if (patDir.equals(&quot;**&quot;)) {</span>
<span class="fc" id="L165"> break;</span>
}
<span class="nc bnc" id="L167" title="All 2 branches missed."> if (!matchStrings(patDir, pathDirs[pathIdxEnd])) {</span>
<span class="nc" id="L168"> return false;</span>
}
<span class="nc" id="L170"> pattIdxEnd--;</span>
<span class="nc" id="L171"> pathIdxEnd--;</span>
<span class="nc" id="L172"> }</span>
<span class="pc bpc" id="L173" title="1 of 2 branches missed."> if (pathIdxStart &gt; pathIdxEnd) {</span>
// String is exhausted
<span class="nc bnc" id="L175" title="All 2 branches missed."> for (int i = pattIdxStart; i &lt;= pattIdxEnd; i++) {</span>
<span class="nc bnc" id="L176" title="All 2 branches missed."> if (!pattDirs[i].equals(&quot;**&quot;)) {</span>
<span class="nc" id="L177"> return false;</span>
}
}
<span class="nc" id="L180"> return true;</span>
}
<span class="pc bpc" id="L183" title="3 of 4 branches missed."> while (pattIdxStart != pattIdxEnd &amp;&amp; pathIdxStart &lt;= pathIdxEnd) {</span>
<span class="nc" id="L184"> int patIdxTmp = -1;</span>
<span class="nc bnc" id="L185" title="All 2 branches missed."> for (int i = pattIdxStart + 1; i &lt;= pattIdxEnd; i++) {</span>
<span class="nc bnc" id="L186" title="All 2 branches missed."> if (pattDirs[i].equals(&quot;**&quot;)) {</span>
<span class="nc" id="L187"> patIdxTmp = i;</span>
<span class="nc" id="L188"> break;</span>
}
}
<span class="nc bnc" id="L191" title="All 2 branches missed."> if (patIdxTmp == pattIdxStart + 1) {</span>
// '**/**' situation, so skip one
<span class="nc" id="L193"> pattIdxStart++;</span>
<span class="nc" id="L194"> continue;</span>
}
// Find the pattern between padIdxStart &amp; padIdxTmp in str between
// strIdxStart &amp; strIdxEnd
<span class="nc" id="L198"> int patLength = (patIdxTmp - pattIdxStart - 1);</span>
<span class="nc" id="L199"> int strLength = (pathIdxEnd - pathIdxStart + 1);</span>
<span class="nc" id="L200"> int foundIdx = -1;</span>
strLoop:
<span class="nc bnc" id="L203" title="All 2 branches missed."> for (int i = 0; i &lt;= strLength - patLength; i++) {</span>
<span class="nc bnc" id="L204" title="All 2 branches missed."> for (int j = 0; j &lt; patLength; j++) {</span>
<span class="nc" id="L205"> String subPat = (String) pattDirs[pattIdxStart + j + 1];</span>
<span class="nc" id="L206"> String subStr = (String) pathDirs[pathIdxStart + i + j];</span>
<span class="nc bnc" id="L207" title="All 2 branches missed."> if (!matchStrings(subPat, subStr)) {</span>
<span class="nc" id="L208"> continue strLoop;</span>
}
}
<span class="nc" id="L211"> foundIdx = pathIdxStart + i;</span>
<span class="nc" id="L212"> break;</span>
}
<span class="nc bnc" id="L215" title="All 2 branches missed."> if (foundIdx == -1) {</span>
<span class="nc" id="L216"> return false;</span>
}
<span class="nc" id="L219"> pattIdxStart = patIdxTmp;</span>
<span class="nc" id="L220"> pathIdxStart = foundIdx + patLength;</span>
<span class="nc" id="L221"> }</span>
<span class="fc bfc" id="L223" title="All 2 branches covered."> for (int i = pattIdxStart; i &lt;= pattIdxEnd; i++) {</span>
<span class="pc bpc" id="L224" title="1 of 2 branches missed."> if (!pattDirs[i].equals(&quot;**&quot;)) {</span>
<span class="nc" id="L225"> return false;</span>
}
}
<span class="fc" id="L229"> return true;</span>
}
/**
* Tests whether or not a string matches against a pattern.
* The pattern may contain two special characters:&lt;br&gt;
* '*' means zero or more characters&lt;br&gt;
* '?' means one and only one character
*
* @param pattern pattern to match against.
* Must not be &lt;code&gt;null&lt;/code&gt;.
* @param str string which must be matched against the pattern.
* Must not be &lt;code&gt;null&lt;/code&gt;.
* @return &lt;code&gt;true&lt;/code&gt; if the string matches against the
* pattern, or &lt;code&gt;false&lt;/code&gt; otherwise.
*/
private boolean matchStrings(String pattern, String str) {
<span class="fc" id="L246"> char[] patArr = pattern.toCharArray();</span>
<span class="fc" id="L247"> char[] strArr = str.toCharArray();</span>
<span class="fc" id="L248"> int patIdxStart = 0;</span>
<span class="fc" id="L249"> int patIdxEnd = patArr.length - 1;</span>
<span class="fc" id="L250"> int strIdxStart = 0;</span>
<span class="fc" id="L251"> int strIdxEnd = strArr.length - 1;</span>
char ch;
<span class="fc" id="L254"> boolean containsStar = false;</span>
<span class="fc bfc" id="L255" title="All 2 branches covered."> for (char aPatArr : patArr) {</span>
<span class="pc bpc" id="L256" title="1 of 2 branches missed."> if (aPatArr == '*') {</span>
<span class="nc" id="L257"> containsStar = true;</span>
<span class="nc" id="L258"> break;</span>
}
}
<span class="pc bpc" id="L262" title="1 of 2 branches missed."> if (!containsStar) {</span>
// No '*'s, so we make a shortcut
<span class="fc bfc" id="L264" title="All 2 branches covered."> if (patIdxEnd != strIdxEnd) {</span>
<span class="fc" id="L265"> return false; // Pattern and string do not have the same size</span>
}
<span class="fc bfc" id="L267" title="All 2 branches covered."> for (int i = 0; i &lt;= patIdxEnd; i++) {</span>
<span class="fc" id="L268"> ch = patArr[i];</span>
<span class="pc bpc" id="L269" title="1 of 2 branches missed."> if (ch != '?') {</span>
<span class="fc bfc" id="L270" title="All 2 branches covered."> if (ch != strArr[i]) {</span>
<span class="fc" id="L271"> return false;// Character mismatch</span>
}
}
}
<span class="fc" id="L275"> return true; // String matches against pattern</span>
}
<span class="nc bnc" id="L279" title="All 2 branches missed."> if (patIdxEnd == 0) {</span>
<span class="nc" id="L280"> return true; // Pattern contains only '*', which matches anything</span>
}
// Process characters before first star
<span class="nc bnc" id="L284" title="All 4 branches missed."> while ((ch = patArr[patIdxStart]) != '*' &amp;&amp; strIdxStart &lt;= strIdxEnd) {</span>
<span class="nc bnc" id="L285" title="All 2 branches missed."> if (ch != '?') {</span>
<span class="nc bnc" id="L286" title="All 2 branches missed."> if (ch != strArr[strIdxStart]) {</span>
<span class="nc" id="L287"> return false;// Character mismatch</span>
}
}
<span class="nc" id="L290"> patIdxStart++;</span>
<span class="nc" id="L291"> strIdxStart++;</span>
}
<span class="nc bnc" id="L293" title="All 2 branches missed."> if (strIdxStart &gt; strIdxEnd) {</span>
// All characters in the string are used. Check if only '*'s are
// left in the pattern. If so, we succeeded. Otherwise failure.
<span class="nc bnc" id="L296" title="All 2 branches missed."> for (int i = patIdxStart; i &lt;= patIdxEnd; i++) {</span>
<span class="nc bnc" id="L297" title="All 2 branches missed."> if (patArr[i] != '*') {</span>
<span class="nc" id="L298"> return false;</span>
}
}
<span class="nc" id="L301"> return true;</span>
}
// Process characters after last star
<span class="nc bnc" id="L305" title="All 4 branches missed."> while ((ch = patArr[patIdxEnd]) != '*' &amp;&amp; strIdxStart &lt;= strIdxEnd) {</span>
<span class="nc bnc" id="L306" title="All 2 branches missed."> if (ch != '?') {</span>
<span class="nc bnc" id="L307" title="All 2 branches missed."> if (ch != strArr[strIdxEnd]) {</span>
<span class="nc" id="L308"> return false;// Character mismatch</span>
}
}
<span class="nc" id="L311"> patIdxEnd--;</span>
<span class="nc" id="L312"> strIdxEnd--;</span>
}
<span class="nc bnc" id="L314" title="All 2 branches missed."> if (strIdxStart &gt; strIdxEnd) {</span>
// All characters in the string are used. Check if only '*'s are
// left in the pattern. If so, we succeeded. Otherwise failure.
<span class="nc bnc" id="L317" title="All 2 branches missed."> for (int i = patIdxStart; i &lt;= patIdxEnd; i++) {</span>
<span class="nc bnc" id="L318" title="All 2 branches missed."> if (patArr[i] != '*') {</span>
<span class="nc" id="L319"> return false;</span>
}
}
<span class="nc" id="L322"> return true;</span>
}
// process pattern between stars. padIdxStart and patIdxEnd point
// always to a '*'.
<span class="nc bnc" id="L327" title="All 4 branches missed."> while (patIdxStart != patIdxEnd &amp;&amp; strIdxStart &lt;= strIdxEnd) {</span>
<span class="nc" id="L328"> int patIdxTmp = -1;</span>
<span class="nc bnc" id="L329" title="All 2 branches missed."> for (int i = patIdxStart + 1; i &lt;= patIdxEnd; i++) {</span>
<span class="nc bnc" id="L330" title="All 2 branches missed."> if (patArr[i] == '*') {</span>
<span class="nc" id="L331"> patIdxTmp = i;</span>
<span class="nc" id="L332"> break;</span>
}
}
<span class="nc bnc" id="L335" title="All 2 branches missed."> if (patIdxTmp == patIdxStart + 1) {</span>
// Two stars next to each other, skip the first one.
<span class="nc" id="L337"> patIdxStart++;</span>
<span class="nc" id="L338"> continue;</span>
}
// Find the pattern between padIdxStart &amp; padIdxTmp in str between
// strIdxStart &amp; strIdxEnd
<span class="nc" id="L342"> int patLength = (patIdxTmp - patIdxStart - 1);</span>
<span class="nc" id="L343"> int strLength = (strIdxEnd - strIdxStart + 1);</span>
<span class="nc" id="L344"> int foundIdx = -1;</span>
strLoop:
<span class="nc bnc" id="L346" title="All 2 branches missed."> for (int i = 0; i &lt;= strLength - patLength; i++) {</span>
<span class="nc bnc" id="L347" title="All 2 branches missed."> for (int j = 0; j &lt; patLength; j++) {</span>
<span class="nc" id="L348"> ch = patArr[patIdxStart + j + 1];</span>
<span class="nc bnc" id="L349" title="All 2 branches missed."> if (ch != '?') {</span>
<span class="nc bnc" id="L350" title="All 2 branches missed."> if (ch != strArr[strIdxStart + i + j]) {</span>
<span class="nc" id="L351"> continue strLoop;</span>
}
}
}
<span class="nc" id="L356"> foundIdx = strIdxStart + i;</span>
<span class="nc" id="L357"> break;</span>
}
<span class="nc bnc" id="L360" title="All 2 branches missed."> if (foundIdx == -1) {</span>
<span class="nc" id="L361"> return false;</span>
}
<span class="nc" id="L364"> patIdxStart = patIdxTmp;</span>
<span class="nc" id="L365"> strIdxStart = foundIdx + patLength;</span>
<span class="nc" id="L366"> }</span>
// All characters in the string are used. Check if only '*'s are left
// in the pattern. If so, we succeeded. Otherwise failure.
<span class="nc bnc" id="L370" title="All 2 branches missed."> for (int i = patIdxStart; i &lt;= patIdxEnd; i++) {</span>
<span class="nc bnc" id="L371" title="All 2 branches missed."> if (patArr[i] != '*') {</span>
<span class="nc" id="L372"> return false;</span>
}
}
<span class="nc" id="L376"> return true;</span>
}
/**
* Given a pattern and a full path, determine the pattern-mapped part.
* &lt;p&gt;For example:
* &lt;ul&gt;
* &lt;li&gt;'&lt;code&gt;/docs/cvs/commit.html&lt;/code&gt;' and '&lt;code&gt;/docs/cvs/commit.html&lt;/code&gt; -&gt; ''&lt;/li&gt;
* &lt;li&gt;'&lt;code&gt;/docs/*&lt;/code&gt;' and '&lt;code&gt;/docs/cvs/commit&lt;/code&gt; -&gt; '&lt;code&gt;cvs/commit&lt;/code&gt;'&lt;/li&gt;
* &lt;li&gt;'&lt;code&gt;/docs/cvs/*.html&lt;/code&gt;' and '&lt;code&gt;/docs/cvs/commit.html&lt;/code&gt; -&gt; '&lt;code&gt;commit.html&lt;/code&gt;'&lt;/li&gt;
* &lt;li&gt;'&lt;code&gt;/docs/**&lt;/code&gt;' and '&lt;code&gt;/docs/cvs/commit&lt;/code&gt; -&gt; '&lt;code&gt;cvs/commit&lt;/code&gt;'&lt;/li&gt;
* &lt;li&gt;'&lt;code&gt;/docs/**\/*.html&lt;/code&gt;' and '&lt;code&gt;/docs/cvs/commit.html&lt;/code&gt; -&gt; '&lt;code&gt;cvs/commit.html&lt;/code&gt;'&lt;/li&gt;
* &lt;li&gt;'&lt;code&gt;/*.html&lt;/code&gt;' and '&lt;code&gt;/docs/cvs/commit.html&lt;/code&gt; -&gt; '&lt;code&gt;docs/cvs/commit.html&lt;/code&gt;'&lt;/li&gt;
* &lt;li&gt;'&lt;code&gt;*.html&lt;/code&gt;' and '&lt;code&gt;/docs/cvs/commit.html&lt;/code&gt; -&gt; '&lt;code&gt;/docs/cvs/commit.html&lt;/code&gt;'&lt;/li&gt;
* &lt;li&gt;'&lt;code&gt;*&lt;/code&gt;' and '&lt;code&gt;/docs/cvs/commit.html&lt;/code&gt; -&gt; '&lt;code&gt;/docs/cvs/commit.html&lt;/code&gt;'&lt;/li&gt;
* &lt;/ul&gt;
* &lt;p&gt;Assumes that {@link #match} returns &lt;code&gt;true&lt;/code&gt; for '&lt;code&gt;pattern&lt;/code&gt;'
* and '&lt;code&gt;path&lt;/code&gt;', but does &lt;strong&gt;not&lt;/strong&gt; enforce this.
*/
public String extractPathWithinPattern(String pattern, String path) {
<span class="nc" id="L396"> String[] patternParts = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator);</span>
<span class="nc" id="L397"> String[] pathParts = StringUtils.tokenizeToStringArray(path, this.pathSeparator);</span>
<span class="nc" id="L399"> StringBuilder buffer = new StringBuilder();</span>
// Add any path parts that have a wildcarded pattern part.
<span class="nc" id="L402"> int puts = 0;</span>
<span class="nc bnc" id="L403" title="All 2 branches missed."> for (int i = 0; i &lt; patternParts.length; i++) {</span>
<span class="nc" id="L404"> String patternPart = patternParts[i];</span>
<span class="nc bnc" id="L405" title="All 6 branches missed."> if ((patternPart.indexOf('*') &gt; -1 || patternPart.indexOf('?') &gt; -1) &amp;&amp; pathParts.length &gt;= i + 1) {</span>
<span class="nc bnc" id="L406" title="All 6 branches missed."> if (puts &gt; 0 || (i == 0 &amp;&amp; !pattern.startsWith(this.pathSeparator))) {</span>
<span class="nc" id="L407"> buffer.append(this.pathSeparator);</span>
}
<span class="nc" id="L409"> buffer.append(pathParts[i]);</span>
<span class="nc" id="L410"> puts++;</span>
}
}
// Append any trailing path parts.
<span class="nc bnc" id="L415" title="All 2 branches missed."> for (int i = patternParts.length; i &lt; pathParts.length; i++) {</span>
<span class="nc bnc" id="L416" title="All 4 branches missed."> if (puts &gt; 0 || i &gt; 0) {</span>
<span class="nc" id="L417"> buffer.append(this.pathSeparator);</span>
}
<span class="nc" id="L419"> buffer.append(pathParts[i]);</span>
}
<span class="nc" id="L422"> return buffer.toString();</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.3.201901230119</span></div></body></html>