1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-07-08 12:57:57 +02:00

Re-work unescaping arguments in parser

Related issue:
https://github.com/uBlockOrigin/uAssets/issues/5184#issuecomment-1803455520
This commit is contained in:
Raymond Hill 2023-11-09 09:11:59 -05:00
parent 2bc7996d64
commit ec53a8f2c7
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2

View File

@ -599,11 +599,6 @@ const exCharCodeAt = (s, i) => {
return pos >= 0 ? s.charCodeAt(pos) : -1;
};
const toEscapedCharRegex = c => {
const safe = c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
return new RegExp(`((?:^|[^\\\\])(?:\\\\\\\\)*)\\\\${safe}`, 'g');
};
/******************************************************************************/
class ArgListParser {
@ -619,11 +614,7 @@ class ArgListParser {
this.reWhitespaceStart = /^\s+/;
this.reWhitespaceEnd = /\s+$/;
this.reOddTrailingEscape = /(?:^|[^\\])(?:\\\\)*\\$/;
this.reEscapedDoubleQuote = toEscapedCharRegex('"');
this.reEscapedSingleQuote = toEscapedCharRegex("'");
this.reEscapedBacktick = toEscapedCharRegex('`');
this.reEscapedSeparator = toEscapedCharRegex(this.separatorChar);
this.unescapedSeparator = `$1${this.separatorChar}`;
this.reTrailingEscapeChars = /\\+$/;
}
nextArg(pattern, beg = 0) {
const len = pattern.length;
@ -655,22 +646,23 @@ class ArgListParser {
}
return this;
}
normalizeArg(s) {
switch ( this.actualSeparatorCode ) {
case 0x22 /* " */:
if ( s.includes('"') === false ) { return; }
return s.replace(this.reEscapedDoubleQuote, '$1"');
case 0x27 /* ' */:
if ( s.includes("'") === false ) { return; }
return s.replace(this.reEscapedSingleQuote, "$1'");
case 0x60 /* ` */:
if ( s.includes('`') === false ) { return; }
return s.replace(this.reEscapedBacktick, '$1`');
default:
break;
normalizeArg(s, char = '') {
if ( char === '' ) { char = this.actualSeparatorChar; }
let out = '';
let pos = 0;
while ( (pos = s.lastIndexOf(char)) !== -1 ) {
out = s.slice(pos) + out;
s = s.slice(0, pos);
const match = this.reTrailingEscapeChars.exec(s);
if ( match === null ) { continue; }
const tail = (match[0].length & 1) !== 0
? match[0].slice(0, -1)
: match[0];
out = tail + out;
s = s.slice(0, -match[0].length);
}
if ( s.includes(this.separatorChar) === false ) { return; }
return s.replace(this.reEscapedSeparator, this.unescapedSeparator);
if ( out === '' ) { return s; }
return s + out;
}
leftWhitespaceCount(s) {
const match = this.reWhitespaceStart.exec(s);
@ -3006,7 +2998,6 @@ export function parseHeaderValue(arg) {
export function parseReplaceValue(s) {
if ( s.charCodeAt(0) !== 0x2F /* / */ ) { return; }
const { reEscapedComma, reEscapedDollarSign } = parseReplaceValue;
const parser = new ArgListParser('/');
parser.nextArg(s, 1);
let pattern = s.slice(parser.argBeg, parser.argEnd);
@ -3014,26 +3005,22 @@ export function parseReplaceValue(s) {
pattern = parser.normalizeArg(pattern);
}
if ( pattern === '' ) { return; }
pattern = pattern
.replace(reEscapedDollarSign, '$1$$$')
.replace(reEscapedComma, '$1,');
pattern = parser.normalizeArg(pattern, '$');
pattern = parser.normalizeArg(pattern, ',');
parser.nextArg(s, parser.separatorEnd);
let replacement = s.slice(parser.argBeg, parser.argEnd);
if ( parser.separatorEnd === parser.separatorBeg ) { return; }
if ( parser.transform ) {
replacement = parser.normalizeArg(replacement);
}
replacement = replacement
.replace(reEscapedDollarSign, '$1$$')
.replace(reEscapedComma, '$1,');
replacement = parser.normalizeArg(replacement, '$');
replacement = parser.normalizeArg(replacement, ',');
const flags = s.slice(parser.separatorEnd);
try {
return { re: new RegExp(pattern, flags), replacement };
} catch(_) {
}
}
parseReplaceValue.reEscapedDollarSign = toEscapedCharRegex('$');
parseReplaceValue.reEscapedComma = toEscapedCharRegex(',');
/******************************************************************************/