Skip to content
Permalink
Browse files

SLD / Filter encoding: fix again escaping of REGEX special characters (

…fixes #5658)
  • Loading branch information...
rouault committed Jan 30, 2019
1 parent 90583b0 commit 9e654b36c296d14e45f854d8ecea684c8b75e441
@@ -41,7 +41,7 @@ char *FLTGetIsLikeComparisonCommonExpression(FilterEncodingNode *psFilterNode)
{
const size_t bufferSize = 1024;
char szBuffer[1024];
char szTmp[256];
char szTmp[512];
char *pszValue = NULL;

const char *pszWild = NULL;
@@ -52,9 +52,9 @@ char *FLTGetIsLikeComparisonCommonExpression(FilterEncodingNode *psFilterNode)

int nLength=0, i=0, iTmp=0;

/* From http://www.fon.hum.uva.nl/praat/manual/Regular_expressions_1__Special_characters.html */
/* From http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html#tag_09_04 */
/* also add double quote because we are within a string */
const char* pszRegexSpecialCharsAndDoubleQuote = "\\^${}[]().*+?|<>-&\"";
const char* pszRegexSpecialCharsAndDoubleQuote = "\\^${[().*+?|\"";

if (!psFilterNode || !psFilterNode->pOther || !psFilterNode->psLeftNode || !psFilterNode->psRightNode || !psFilterNode->psRightNode->pszValue)
return NULL;
@@ -92,11 +92,12 @@ char *FLTGetIsLikeComparisonCommonExpression(FilterEncodingNode *psFilterNode)

pszValue = psFilterNode->psRightNode->pszValue;
nLength = strlen(pszValue);
if( 1 + 2 * nLength + 1 + 1 >= sizeof(szTmp) )
/* The 4 factor is in case of \. See below */
if( 1 + 4 * nLength + 1 + 1 >= sizeof(szTmp) )
return NULL;

iTmp =0;
if (nLength > 0 && pszValue[0] != pszWild[0] && pszValue[0] != pszSingle[0] && pszValue[0] != pszEscape[0]) {
if (nLength > 0) {
szTmp[iTmp]= '^';
iTmp++;
}
@@ -106,21 +107,33 @@ char *FLTGetIsLikeComparisonCommonExpression(FilterEncodingNode *psFilterNode)
iTmp++;
szTmp[iTmp] = '\0';
/* The Filter escape character is supposed to only escape the single, wildcard and escape character */
/* As we replace single and wild by regular expression special characters, we indeed */
/* need to escape them */
} else if (pszValue[i] == pszEscape[0] && (pszValue[i+1] == pszSingle[0] || pszValue[i+1] == pszWild[0])) {
szTmp[iTmp] = '\\';
iTmp++;
szTmp[iTmp] = '\0';
/* If the Filter escape character is escaped, only regular-expression-escape-it */
/* if it is indeed a regular expression special character. Otherwise ignore it */
} else if (pszValue[i] == pszEscape[0] && pszValue[i+1] == pszEscape[0]) {
if( strchr(pszRegexSpecialCharsAndDoubleQuote, pszValue[i]) )
} else if (pszValue[i] == pszEscape[0] && (
pszValue[i+1] == pszSingle[0] ||
pszValue[i+1] == pszWild[0] ||
pszValue[i+1] == pszEscape[0])) {
if( pszValue[i+1] == '\\' )
{
/* Tricky case: \ must be escaped ncce in the regular expression context
so that the regexp matches it as an ordinary character.
But as \ is also the escape character for MapServer string, we
must escape it again. */
szTmp[iTmp++] = '\\';
szTmp[iTmp++] = '\\';
szTmp[iTmp++] = '\\';
szTmp[iTmp++] = '\\';
}
else
{
szTmp[iTmp] = '\\';
iTmp++;
szTmp[iTmp] = '\0';
/* If the escaped character is itself a regular expression special character */
/* we need to regular-expression-escape-it ! */
if( strchr(pszRegexSpecialCharsAndDoubleQuote, pszValue[i+1]) )
{
szTmp[iTmp++] = '\\';
}
szTmp[iTmp++] = pszValue[i+1];
}
i++;
szTmp[iTmp] = '\0';
} else if (pszValue[i] == pszWild[0]) {
szTmp[iTmp++] = '.';
szTmp[iTmp++] = '*';
@@ -129,10 +142,19 @@ char *FLTGetIsLikeComparisonCommonExpression(FilterEncodingNode *psFilterNode)
/* Escape regular expressions special characters and double quote */
else if (strchr(pszRegexSpecialCharsAndDoubleQuote, pszValue[i]))
{
szTmp[iTmp] = '\\';
iTmp++;
szTmp[iTmp] = pszValue[i];
iTmp++;
if( pszValue[i] == '\\' )
{
/* See above explantation */
szTmp[iTmp++] = '\\';
szTmp[iTmp++] = '\\';
szTmp[iTmp++] = '\\';
szTmp[iTmp++] = '\\';
}
else
{
szTmp[iTmp++] = '\\';
szTmp[iTmp++] = pszValue[i];
}
szTmp[iTmp] = '\0';
}
else {
@@ -143,7 +165,10 @@ char *FLTGetIsLikeComparisonCommonExpression(FilterEncodingNode *psFilterNode)
}
szTmp[iTmp] = '"';
szTmp[++iTmp] = '\0';

#if 0
msDebug("like: %s\n", pszValue);
msDebug("regexp (with \\ escaping for MapServer use): %s\n", szTmp);
#endif
strlcat(szBuffer, szTmp, bufferSize);
strlcat(szBuffer, ")", bufferSize);
return msStrdup(szBuffer);
@@ -1,3 +1,3 @@
id,prop,WKT
1,"()[].yxabc","LINESTRING(-67.5725 42,-58.9275 48.5)"
1,"\^${}[]().*+-?|""abcde","LINESTRING(-67.5725 42,-58.9275 48.5)"
2,"x","LINESTRING(-67.5725 42,-58.9275 48.5)"
Binary file not shown.
@@ -27,7 +27,7 @@ Content-Type: text/xml; charset=UTF-8
</gml:LineString>
</ms:msGeometry>
<ms:id>1</ms:id>
<ms:prop>()[].yxabc</ms:prop>
<ms:prop>\^${}[]().*+-?|&quot;abcde</ms:prop>
</ms:test_islike_escaping>
</gml:featureMember>
</wfs:FeatureCollection>
@@ -53,7 +53,10 @@
# Verify PropertyIsLike
# RUN_PARMS: wfs_filter_islike.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=popplace&FILTER=<Filter><PropertyIsLike+wildCard='*'+singleChar='.'+escape='!'><PropertyName>NAME</PropertyName><Literal>Syd*</Literal></PropertyIsLike></Filter>" > [RESULT]
#
# RUN_PARMS: wfs_filter_islike_escaping.xml [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=test_islike_escaping&FILTER=<Filter><PropertyIsLike+wildCard='*'+singleChar='.'+escape='^'><PropertyName>prop</PropertyName><Literal>()[]^..x*c</Literal></PropertyIsLike></Filter>" > [RESULT]
# RUN_PARMS: wfs_filter_islike_escaping.xml [MAPSERV] QUERY_STRING='map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=test_islike_escaping&FILTER=<Filter><PropertyIsLike+wildCard="*"+singleChar="."+escape="^"><PropertyName>prop</PropertyName><Literal>\^^${}[]()^.^*%2B-?|"a.*e</Literal></PropertyIsLike></Filter>' > [RESULT]
#
# Again but use as an escape character the regexp escape character
# RUN_PARMS: wfs_filter_islike_escaping.xml [MAPSERV] QUERY_STRING='map=[MAPFILE]&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=test_islike_escaping&FILTER=<Filter><PropertyIsLike+wildCard="*"+singleChar="."+escape="\"><PropertyName>prop</PropertyName><Literal>\\^${}[]()\.\*%2B-?|"a.*e</Literal></PropertyIsLike></Filter>' > [RESULT]
#
#
# RUN_PARMS: wfs_filter_200_islike.xml [MAPSERV] [POST]<?xml version="1.0"?><GetFeature service="WFS" version="2.0.0" xmlns:fes="http://www.opengis.net/fes/2.0" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns="http://www.opengis.net/wfs/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/fes/2.0 http://schemas.opengis.net/filter/2.0/filterAll.xsd http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd"><Query typeNames="popplace"><fes:Filter><fes:PropertyIsLike wildCard='*' singleChar='.' escapeChar='!'><fes:ValueReference>NAME</fes:ValueReference><fes:Literal>Syd*</fes:Literal></fes:PropertyIsLike></fes:Filter></Query></GetFeature>[/POST] > [RESULT_DEVERSION]

0 comments on commit 9e654b3

Please sign in to comment.
You can’t perform that action at this time.