0
0
mirror of https://github.com/TrianguloY/UrlChecker.git synced 2024-09-19 20:02:16 +02:00

Pattern Checker: Fix optional groups giving a null instead of an empty string

Fixes #237
This commit is contained in:
blankie 2023-06-04 22:01:47 +07:00
parent 491cd17c64
commit 72f57e43d9
No known key found for this signature in database
GPG Key ID: CC15FC822C7F61F5

View File

@ -1,5 +1,7 @@
package com.trianguloy.urlchecker.modules.list;
import android.annotation.TargetApi;
import android.os.Build;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
@ -24,6 +26,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
/**
* This module checks for patterns characters in the url
@ -122,7 +125,7 @@ class PatternDialog extends AModuleDialog {
// get regex (must exists)
if (!data.has("regex")) continue;
var regex = data.getString("regex");
Pattern regex = Pattern.compile(data.getString("regex"));
// applied?
message.applied = urlData.getData(APPLIED + pattern) != null;
@ -130,7 +133,7 @@ class PatternDialog extends AModuleDialog {
// check matches
// if 'regexp' matches, the pattern can match
// if 'regexp' doesn't match, the patter doesn't match
var matches = Pattern.compile(regex).matcher(url).find();
var matches = regex.matcher(url).find();
if (matches && data.has("excludeRegex")) {
// if 'excludeRegex' doesn't exist, the pattern can match
// if 'excludeRegex' matches, the pattern doesn't matches
@ -158,7 +161,7 @@ class PatternDialog extends AModuleDialog {
if (replacement != null) {
// replace url
message.newUrl = url.replaceAll(regex, replacement);
message.newUrl = replaceAll(url, regex, replacement);
// automatic? apply
if (data.optBoolean("automatic")) {
@ -225,4 +228,100 @@ class PatternDialog extends AModuleDialog {
this.pattern = pattern;
}
}
/**
* On Android 10 and under, optional groups may yield a "null" in the replacement output instead of an empty string.
* Therefore, we just copy the implementation from newer versions
* https://github.com/TrianguloY/UrlChecker/issues/237
*/
private static String replaceAll(String text, Pattern pattern, String replacement) {
// Copied from https://android.googlesource.com/platform/libcore/+/refs/heads/android13-release/ojluni/src/main/java/java/util/regex/Matcher.java#837
Matcher matcher = pattern.matcher(text);
boolean result = matcher.find();
if (result) {
StringBuffer sb = new StringBuffer();
int appendPos = 0;
do {
appendPos = appendReplacement(text, matcher, sb, replacement, appendPos);
result = matcher.find();
} while (result);
appendTail(text, sb, appendPos);
return sb.toString();
}
return text.toString();
}
private static int appendReplacement(String text, Matcher matcher, StringBuffer sb, String replacement, int appendPos) {
// Copied from https://android.googlesource.com/platform/libcore/+/refs/heads/android13-release/ojluni/src/main/java/java/util/regex/Matcher.java#714
sb.append(text.substring(appendPos, matcher.start()));
appendEvaluated(matcher, sb, replacement);
appendPos = matcher.end();
return appendPos;
}
@TargetApi(Build.VERSION_CODES.O)
private static void appendEvaluated(Matcher matcher, StringBuffer buffer, String s) {
// Copied from https://android.googlesource.com/platform/libcore/+/refs/heads/android13-release/ojluni/src/main/java/java/util/regex/Matcher.java#731
boolean escape = false;
boolean dollar = false;
boolean escapeNamedGroup = false;
int escapeNamedGroupStart = -1;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '\\' && !escape) {
escape = true;
} else if (c == '$' && !escape) {
dollar = true;
} else if (c >= '0' && c <= '9' && dollar && !escapeNamedGroup) {
String groupValue = matcher.group(c - '0');
if (groupValue != null) {
buffer.append(groupValue);
}
dollar = false;
} else if (c == '{' && dollar) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
throw new IllegalArgumentException("your android version does not support named-capturing groups");
}
escapeNamedGroup = true;
escapeNamedGroupStart = i;
} else if (c == '}' && dollar && escapeNamedGroup) {
String groupValue = matcher.group(s.substring(escapeNamedGroupStart + 1, i));
if (groupValue != null) {
buffer.append(groupValue);
}
dollar = false;
escapeNamedGroup = false;
} else if (c != '}' && dollar && escapeNamedGroup) {
continue;
} else {
buffer.append(c);
dollar = false;
escape = false;
escapeNamedGroup = false;
}
}
if (escape) {
throw new IllegalArgumentException("character to be escaped is missing");
}
if (dollar) {
throw new IllegalArgumentException("Illegal group reference: group index is missing");
}
if (escapeNamedGroup) {
throw new IllegalArgumentException("Missing ending brace '}' from replacement string");
}
}
private static StringBuffer appendTail(String text, StringBuffer sb, int appendPos) {
// Copied from https://android.googlesource.com/platform/libcore/+/refs/heads/android13-release/ojluni/src/main/java/java/util/regex/Matcher.java#796
int to = text.length();
if (appendPos < to) {
sb.append(text.substring(appendPos, to));
}
return sb;
}
}