1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache license, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the license for the specific language governing permissions and 15 * limitations under the license. 16 */ 17 package org.apache.logging.log4j.core.lookup; 18 19 import java.util.Arrays; 20 21 /** 22 * A matcher class that can be queried to determine if a character array 23 * portion matches. 24 * <p> 25 * This class comes complete with various factory methods. 26 * If these do not suffice, you can subclass and implement your own matcher. 27 */ 28 public abstract class StrMatcher { 29 30 /** 31 * Matches the comma character. 32 */ 33 private static final StrMatcher COMMA_MATCHER = new CharMatcher(','); 34 /** 35 * Matches the tab character. 36 */ 37 private static final StrMatcher TAB_MATCHER = new CharMatcher('\t'); 38 /** 39 * Matches the space character. 40 */ 41 private static final StrMatcher SPACE_MATCHER = new CharMatcher(' '); 42 /** 43 * Matches the same characters as StringTokenizer, 44 * namely space, tab, newline, formfeed. 45 */ 46 private static final StrMatcher SPLIT_MATCHER = new CharSetMatcher(" \t\n\r\f".toCharArray()); 47 /** 48 * Matches the String trim() whitespace characters. 49 */ 50 private static final StrMatcher TRIM_MATCHER = new TrimMatcher(); 51 /** 52 * Matches the double quote character. 53 */ 54 private static final StrMatcher SINGLE_QUOTE_MATCHER = new CharMatcher('\''); 55 /** 56 * Matches the double quote character. 57 */ 58 private static final StrMatcher DOUBLE_QUOTE_MATCHER = new CharMatcher('"'); 59 /** 60 * Matches the single or double quote character. 61 */ 62 private static final StrMatcher QUOTE_MATCHER = new CharSetMatcher("'\"".toCharArray()); 63 /** 64 * Matches no characters. 65 */ 66 private static final StrMatcher NONE_MATCHER = new NoMatcher(); 67 68 /** 69 * Constructor. 70 */ 71 protected StrMatcher() { 72 } 73 74 /** 75 * Returns a matcher which matches the comma character. 76 * 77 * @return a matcher for a comma 78 */ 79 public static StrMatcher commaMatcher() { 80 return COMMA_MATCHER; 81 } 82 83 /** 84 * Returns a matcher which matches the tab character. 85 * 86 * @return a matcher for a tab 87 */ 88 public static StrMatcher tabMatcher() { 89 return TAB_MATCHER; 90 } 91 92 /** 93 * Returns a matcher which matches the space character. 94 * 95 * @return a matcher for a space 96 */ 97 public static StrMatcher spaceMatcher() { 98 return SPACE_MATCHER; 99 } 100 101 /** 102 * Matches the same characters as StringTokenizer, 103 * namely space, tab, newline and formfeed. 104 * 105 * @return the split matcher 106 */ 107 public static StrMatcher splitMatcher() { 108 return SPLIT_MATCHER; 109 } 110 111 /** 112 * Matches the String trim() whitespace characters. 113 * 114 * @return the trim matcher 115 */ 116 public static StrMatcher trimMatcher() { 117 return TRIM_MATCHER; 118 } 119 120 /** 121 * Returns a matcher which matches the single quote character. 122 * 123 * @return a matcher for a single quote 124 */ 125 public static StrMatcher singleQuoteMatcher() { 126 return SINGLE_QUOTE_MATCHER; 127 } 128 129 /** 130 * Returns a matcher which matches the double quote character. 131 * 132 * @return a matcher for a double quote 133 */ 134 public static StrMatcher doubleQuoteMatcher() { 135 return DOUBLE_QUOTE_MATCHER; 136 } 137 138 /** 139 * Returns a matcher which matches the single or double quote character. 140 * 141 * @return a matcher for a single or double quote 142 */ 143 public static StrMatcher quoteMatcher() { 144 return QUOTE_MATCHER; 145 } 146 147 /** 148 * Matches no characters. 149 * 150 * @return a matcher that matches nothing 151 */ 152 public static StrMatcher noneMatcher() { 153 return NONE_MATCHER; 154 } 155 156 /** 157 * Constructor that creates a matcher from a character. 158 * 159 * @param ch the character to match, must not be null 160 * @return a new Matcher for the given char 161 */ 162 public static StrMatcher charMatcher(char ch) { 163 return new CharMatcher(ch); 164 } 165 166 /** 167 * Constructor that creates a matcher from a set of characters. 168 * 169 * @param chars the characters to match, null or empty matches nothing 170 * @return a new matcher for the given char[] 171 */ 172 public static StrMatcher charSetMatcher(char[] chars) { 173 if (chars == null || chars.length == 0) { 174 return NONE_MATCHER; 175 } 176 if (chars.length == 1) { 177 return new CharMatcher(chars[0]); 178 } 179 return new CharSetMatcher(chars); 180 } 181 182 /** 183 * Constructor that creates a matcher from a string representing a set of characters. 184 * 185 * @param chars the characters to match, null or empty matches nothing 186 * @return a new Matcher for the given characters 187 */ 188 public static StrMatcher charSetMatcher(String chars) { 189 if (chars == null || chars.length() == 0) { 190 return NONE_MATCHER; 191 } 192 if (chars.length() == 1) { 193 return new CharMatcher(chars.charAt(0)); 194 } 195 return new CharSetMatcher(chars.toCharArray()); 196 } 197 198 /** 199 * Constructor that creates a matcher from a string. 200 * 201 * @param str the string to match, null or empty matches nothing 202 * @return a new Matcher for the given String 203 */ 204 public static StrMatcher stringMatcher(String str) { 205 if (str == null || str.length() == 0) { 206 return NONE_MATCHER; 207 } 208 return new StringMatcher(str); 209 } 210 211 /** 212 * Returns the number of matching characters, zero for no match. 213 * <p> 214 * This method is called to check for a match. 215 * The parameter <code>pos</code> represents the current position to be 216 * checked in the string <code>buffer</code> (a character array which must 217 * not be changed). 218 * The API guarantees that <code>pos</code> is a valid index for <code>buffer</code>. 219 * <p> 220 * The character array may be larger than the active area to be matched. 221 * Only values in the buffer between the specifed indices may be accessed. 222 * <p> 223 * The matching code may check one character or many. 224 * It may check characters preceeding <code>pos</code> as well as those 225 * after, so long as no checks exceed the bounds specified. 226 * <p> 227 * It must return zero for no match, or a positive number if a match was found. 228 * The number indicates the number of characters that matched. 229 * 230 * @param buffer the text content to match against, do not change 231 * @param pos the starting position for the match, valid for buffer 232 * @param bufferStart the first active index in the buffer, valid for buffer 233 * @param bufferEnd the end index (exclusive) of the active buffer, valid for buffer 234 * @return the number of matching characters, zero for no match 235 */ 236 public abstract int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd); 237 238 /** 239 * Returns the number of matching characters, zero for no match. 240 * <p> 241 * This method is called to check for a match. 242 * The parameter <code>pos</code> represents the current position to be 243 * checked in the string <code>buffer</code> (a character array which must 244 * not be changed). 245 * The API guarantees that <code>pos</code> is a valid index for <code>buffer</code>. 246 * <p> 247 * The matching code may check one character or many. 248 * It may check characters preceeding <code>pos</code> as well as those after. 249 * <p> 250 * It must return zero for no match, or a positive number if a match was found. 251 * The number indicates the number of characters that matched. 252 * 253 * @param buffer the text content to match against, do not change 254 * @param pos the starting position for the match, valid for buffer 255 * @return the number of matching characters, zero for no match 256 * @since 2.4 257 */ 258 public int isMatch(char[] buffer, int pos) { 259 return isMatch(buffer, pos, 0, buffer.length); 260 } 261 262 //----------------------------------------------------------------------- 263 /** 264 * Class used to define a set of characters for matching purposes. 265 */ 266 static final class CharSetMatcher extends StrMatcher { 267 /** The set of characters to match. */ 268 private final char[] chars; 269 270 /** 271 * Constructor that creates a matcher from a character array. 272 * 273 * @param chars the characters to match, must not be null 274 */ 275 CharSetMatcher(char[] chars) { 276 super(); 277 this.chars = chars.clone(); 278 Arrays.sort(this.chars); 279 } 280 281 /** 282 * Returns whether or not the given character matches. 283 * 284 * @param buffer the text content to match against, do not change 285 * @param pos the starting position for the match, valid for buffer 286 * @param bufferStart the first active index in the buffer, valid for buffer 287 * @param bufferEnd the end index of the active buffer, valid for buffer 288 * @return the number of matching characters, zero for no match 289 */ 290 @Override 291 public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) { 292 return Arrays.binarySearch(chars, buffer[pos]) >= 0 ? 1 : 0; 293 } 294 } 295 296 //----------------------------------------------------------------------- 297 /** 298 * Class used to define a character for matching purposes. 299 */ 300 static final class CharMatcher extends StrMatcher { 301 /** The character to match. */ 302 private final char ch; 303 304 /** 305 * Constructor that creates a matcher that matches a single character. 306 * 307 * @param ch the character to match 308 */ 309 CharMatcher(char ch) { 310 super(); 311 this.ch = ch; 312 } 313 314 /** 315 * Returns whether or not the given character matches. 316 * 317 * @param buffer the text content to match against, do not change 318 * @param pos the starting position for the match, valid for buffer 319 * @param bufferStart the first active index in the buffer, valid for buffer 320 * @param bufferEnd the end index of the active buffer, valid for buffer 321 * @return the number of matching characters, zero for no match 322 */ 323 @Override 324 public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) { 325 return ch == buffer[pos] ? 1 : 0; 326 } 327 } 328 329 //----------------------------------------------------------------------- 330 /** 331 * Class used to define a set of characters for matching purposes. 332 */ 333 static final class StringMatcher extends StrMatcher { 334 /** The string to match, as a character array. */ 335 private final char[] chars; 336 337 /** 338 * Constructor that creates a matcher from a String. 339 * 340 * @param str the string to match, must not be null 341 */ 342 StringMatcher(String str) { 343 super(); 344 chars = str.toCharArray(); 345 } 346 347 /** 348 * Returns whether or not the given text matches the stored string. 349 * 350 * @param buffer the text content to match against, do not change 351 * @param pos the starting position for the match, valid for buffer 352 * @param bufferStart the first active index in the buffer, valid for buffer 353 * @param bufferEnd the end index of the active buffer, valid for buffer 354 * @return the number of matching characters, zero for no match 355 */ 356 @Override 357 public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) { 358 int len = chars.length; 359 if (pos + len > bufferEnd) { 360 return 0; 361 } 362 for (int i = 0; i < chars.length; i++, pos++) { 363 if (chars[i] != buffer[pos]) { 364 return 0; 365 } 366 } 367 return len; 368 } 369 } 370 371 //----------------------------------------------------------------------- 372 /** 373 * Class used to match no characters. 374 */ 375 static final class NoMatcher extends StrMatcher { 376 377 /** 378 * Constructs a new instance of <code>NoMatcher</code>. 379 */ 380 NoMatcher() { 381 super(); 382 } 383 384 /** 385 * Always returns {@code false}. 386 * 387 * @param buffer the text content to match against, do not change 388 * @param pos the starting position for the match, valid for buffer 389 * @param bufferStart the first active index in the buffer, valid for buffer 390 * @param bufferEnd the end index of the active buffer, valid for buffer 391 * @return the number of matching characters, zero for no match 392 */ 393 @Override 394 public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) { 395 return 0; 396 } 397 } 398 399 //----------------------------------------------------------------------- 400 /** 401 * Class used to match whitespace as per trim(). 402 */ 403 static final class TrimMatcher extends StrMatcher { 404 405 /** 406 * Constructs a new instance of <code>TrimMatcher</code>. 407 */ 408 TrimMatcher() { 409 super(); 410 } 411 412 /** 413 * Returns whether or not the given character matches. 414 * 415 * @param buffer the text content to match against, do not change 416 * @param pos the starting position for the match, valid for buffer 417 * @param bufferStart the first active index in the buffer, valid for buffer 418 * @param bufferEnd the end index of the active buffer, valid for buffer 419 * @return the number of matching characters, zero for no match 420 */ 421 @Override 422 public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) { 423 return buffer[pos] <= ' ' ? 1 : 0; 424 } 425 } 426 427 }