Skip to content

Commit

Permalink
Add support for PCRE2 (to replace deprecated PCRE) (fixes #4822)
Browse files Browse the repository at this point in the history
  • Loading branch information
rouault committed Nov 14, 2021
1 parent ab14711 commit 4c187d9
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ubuntu_20.04/build-deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ DEBIAN_FRONTEND=noninteractive apt-get install -y --fix-missing --no-install-rec
libnetcdf-dev libpoppler-dev libpoppler-private-dev \
libspatialite-dev swig libhdf4-alt-dev libhdf5-serial-dev \
libfreexl-dev unixodbc-dev libwebp-dev libepsilon-dev \
liblcms2-2 libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev \
liblcms2-2 libpcre2-dev libcrypto++-dev libdap-dev libfyba-dev \
libkml-dev libmysqlclient-dev libogdi-dev \
libcfitsio-dev openjdk-8-jdk libzstd-dev \
libpq-dev libssl-dev libboost-dev \
Expand Down
1 change: 1 addition & 0 deletions GDALmake.opt.in
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ SPATIALITE_SONAME = @SPATIALITE_SONAME@
SPATIALITE_INC = @SPATIALITE_INC@
SPATIALITE_412_OR_LATER = @SPATIALITE_412_OR_LATER@
HAVE_PCRE = @HAVE_PCRE@
HAVE_PCRE2 = @HAVE_PCRE2@
HAVE_RASTERLITE2 = @HAVE_RASTERLITE2@
RASTERLITE2_CFLAGS = @RASTERLITE2_CFLAGS@

Expand Down
40 changes: 39 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -4430,6 +4430,43 @@ fi
AC_SUBST([HAVE_RASTERLITE2], $HAVE_RASTERLITE2)
AC_SUBST([RASTERLITE2_CFLAGS], $RASTERLITE2_CFLAGS)

dnl ---------------------------------------------------------------------------
dnl Check for PCRE2.
dnl ---------------------------------------------------------------------------

HAVE_PCRE2=no

AC_ARG_WITH(pcre2,
[ --with-pcre2 Include libpcre2 support (REGEXP support for SQLite)],
,,)

if test "$with_pcre2" = "no"; then
AC_MSG_RESULT(disabled)
HAVE_PCRE2=no
else
save_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS -DPCRE2_CODE_UNIT_WIDTH=8"
AC_CHECK_HEADERS([pcre2.h])
CPPFLAGS="$save_CPPFLAGS"
if test "$ac_cv_header_pcre2_h" = "no" ; then
if test "$with_pcre2" = "yes"; then
AC_MSG_ERROR([cannot find pcre2.h])
fi
else
AC_CHECK_LIB(pcre2-8,pcre2_compile_8,HAVE_PCRE2=yes,HAVE_PCRE2=no,)
if test "$HAVE_PCRE2" = "yes" ; then
HAVE_PCRE2=yes
LIBS="$LIBS -lpcre2-8"
else
if test "$with_pcre2" = "yes"; then
AC_MSG_ERROR([cannot find libpcre2])
fi
fi
fi
fi

AC_SUBST(HAVE_PCRE2)

dnl ---------------------------------------------------------------------------
dnl Check for PCRE.
dnl ---------------------------------------------------------------------------
Expand All @@ -4443,7 +4480,7 @@ AC_ARG_WITH(pcre,
if test "$with_pcre" = "no"; then
AC_MSG_RESULT(disabled)
HAVE_PCRE=no
else
elif test "$HAVE_PCRE2" = "no"; then
AC_CHECK_HEADERS([pcre.h])
if test "$ac_cv_header_pcre_h" = "no" ; then
if test "$with_pcre" = "yes"; then
Expand Down Expand Up @@ -6251,6 +6288,7 @@ LOC_MSG([ OpenJPEG support: ${HAVE_OPENJPEG}])
LOC_MSG([ PCIDSK support: ${PCIDSK_SETTING}])
LOC_MSG([ PCRaster support: ${PCRASTER_SETTING}])
LOC_MSG([ PCRE support: ${HAVE_PCRE}])
LOC_MSG([ PCRE2 support: ${HAVE_PCRE2}])
LOC_MSG([ PDFium support: ${HAVE_PDFIUM}])
LOC_MSG([ Podofo support: ${HAVE_PODOFO}])
LOC_MSG([ Poppler support: ${HAVE_POPPLER}])
Expand Down
8 changes: 6 additions & 2 deletions nmake.opt
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,11 @@ INGRES_LIB = "$(INGRES_HOME)\lib\iilibapi.lib" \
# Uncomment following line if spatialite is 4.1.2 or later
#SPATIALITE_412_OR_LATER=yes

# PCRE Library (REGEXP support for SQLite) for example from http://sourceforge.net/projects/gnuwin32/files/pcre/7.0/pcre-7.0.exe/download
# PCRE2 Library (REGEXP support for SQLite)
#PCRE2_INC=-I"C:\dev\install-pcre2\include" -DHAVE_PCRE2
#PCRE2_LIB="C:\dev\install-pcre2\lib\pcre2-8.lib"

# Deprecated: PCRE Library (REGEXP support for SQLite) for example from http://sourceforge.net/projects/gnuwin32/files/pcre/7.0/pcre-7.0.exe/download
#PCRE_INC=-I"C:\Program Files\GNUWin32\include" -DHAVE_PCRE
#PCRE_LIB="C:\Program Files\GNUWin32\lib\pcre.lib"

Expand Down Expand Up @@ -1180,6 +1184,6 @@ EXTERNAL_LIBS = $(OGDILIB) $(XERCES_LIB) $(EXPAT_LIB) $(OCI_LIB) $(PG_LIB) \
$(ODBCLIB) $(JASPER_LIB) $(PNG_LIB) $(ZLIB_LIB) $(LIBDEFLATE_LIB) $(ADD_LIBS) $(OPENJPEG_LIB) \
$(MRSID_LIDAR_LIB) $(LIBKML_LIBS) $(SOSI_LIBS) $(PDF_LIB_LINK) $(LZMA_LIBS) $(ZSTD_LIBS) $(BLOSC_LIBS) $(LZ4_LIBS) \
$(LIBICONV_LIBRARY) $(WEBP_LIBS) $(TILEDB_LIBS) $(FGDB_LIB_LINK) $(FREEXL_LIBS) $(GTA_LIBS) \
$(INGRES_LIB) $(LIBXML2_LIB) $(PCRE_LIB) $(MONGODB_LIB_LINK) $(MONGODBV3_LIB_LINK) $(CRYPTOPP_LIB) $(OPENSSL_LIB) $(CHARLS_LIB) ws2_32.lib \
$(INGRES_LIB) $(LIBXML2_LIB) $(PCRE_LIB) $(PCRE2_LIB) $(MONGODB_LIB_LINK) $(MONGODBV3_LIB_LINK) $(CRYPTOPP_LIB) $(OPENSSL_LIB) $(CHARLS_LIB) ws2_32.lib \
$(RDB_LIB) $(CRUNCH_LIB) $(OPENEXR_LIB) $(HEIF_LIB) $(LERC_LIB) $(JXL_LIB) $(BROTLI_LIB) $(BRUNSLI_LIB)\
kernel32.lib psapi.lib wbemuuid.lib
4 changes: 4 additions & 0 deletions ogr/ogrsf_frmts/sqlite/GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ ifeq ($(HAVE_PCRE),yes)
CPPFLAGS += -DHAVE_PCRE
endif

ifeq ($(HAVE_PCRE2),yes)
CPPFLAGS += -DHAVE_PCRE2
endif

ifeq ($(SQLITE_HAS_COLUMN_METADATA),yes)
CPPFLAGS += -DSQLITE_HAS_COLUMN_METADATA
endif
Expand Down
4 changes: 3 additions & 1 deletion ogr/ogrsf_frmts/sqlite/makefile.vc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ GDAL_ROOT = ..\..\..

EXTRAFLAGS = -I.. -I..\.. $(PROJ_FLAGS) $(PROJ_INCLUDE) $(SQLITE_INC) $(PCRE_EXTRAFLAGS) $(SQLITE_HAS_COLUMN_METADATA_EXTRAFLAGS) $(SPATIALITE_412_OR_LATER_EXTRAFLAGS) -DSQLITE_HAS_NON_DEPRECATED_AUTO_EXTENSION

!IFDEF PCRE_INC
!IFDEF PCRE2_INC
PCRE_EXTRAFLAGS = $(PCRE2_INC)
!ELSEIFDEF PCRE_INC
PCRE_EXTRAFLAGS = $(PCRE_INC)
!ENDIF

Expand Down
149 changes: 144 additions & 5 deletions ogr/ogrsf_frmts/sqlite/ogrsqliteregexp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,137 @@
* commercial or non-commercial, and by any means.
*/

// The pcre2 variant has been ported from https://github.com/pfmoore/sqlite-pcre2/blob/main/src/pcre.c
// which has the same license as above.

#include "ogrsqliteregexp.h"
#include "sqlite3.h"

#ifdef HAVE_PCRE
#ifdef HAVE_PCRE2

#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>

typedef struct {
char *s;
pcre2_code *p;
} cache_entry;

constexpr int CACHE_SIZE = 16;

static
pcre2_code *re_compile_with_cache(sqlite3_context *ctx, const char *re)
{
cache_entry *cache = static_cast<cache_entry*>(sqlite3_user_data(ctx));

CPLAssert(cache);

bool found = false;
int i;
for (i = 0; i < CACHE_SIZE && cache[i].s; i++)
if (strcmp(re, cache[i].s) == 0) {
found = true;
break;
}

if (found) {
if (i > 0) {
/* Get the found entry */
cache_entry c = cache[i];
/* Move 0..i-1 up one - args are (dest, src, size) */
memmove(cache + 1, cache, i * sizeof(cache_entry));
/* Put the found entry at the start */
cache[0] = c;
}
}
else {
/* Create a new entry */
int errorcode = 0;
PCRE2_SIZE pos = 0;
uint32_t has_jit = 0;
PCRE2_UCHAR8 err_buff[256];

pcre2_code* pat = pcre2_compile(reinterpret_cast<const PCRE2_UCHAR8*>(re),
PCRE2_ZERO_TERMINATED, 0, &errorcode, &pos, nullptr);
if (!pat) {
pcre2_get_error_message(errorcode, err_buff, sizeof(err_buff));
char *e2 = sqlite3_mprintf("%s: %s (offset %d)", re, err_buff, pos);
sqlite3_result_error(ctx, e2, -1);
sqlite3_free(e2);
return nullptr;
}
pcre2_config(PCRE2_CONFIG_JIT, &has_jit);
if (has_jit) {
errorcode = pcre2_jit_compile(pat, 0);
if (errorcode) {
pcre2_get_error_message(errorcode, err_buff, sizeof(err_buff));
char *e2 = sqlite3_mprintf("%s: %s", re, err_buff);
sqlite3_result_error(ctx, e2, -1);
sqlite3_free(e2);
pcre2_code_free(pat);
return nullptr;
}
}
/* Free the last cache entry if necessary */
i = CACHE_SIZE - 1;
if (cache[i].s) {
VSIFree(cache[i].s);
CPLAssert(cache[i].p);
pcre2_code_free(cache[i].p);
}
/* Move everything up to make space */
memmove(cache + 1, cache, i * sizeof(cache_entry));
cache[0].s = VSIStrdup(re);
cache[0].p = pat;
}

return cache[0].p;
}

/************************************************************************/
/* OGRSQLiteREGEXPFunction() */
/************************************************************************/

static
void OGRSQLiteREGEXPFunction( sqlite3_context *ctx,
CPL_UNUSED int argc, sqlite3_value **argv )
{
CPLAssert(argc == 2);

const char *re = (const char *) sqlite3_value_text(argv[0]);
if (!re) {
sqlite3_result_error(ctx, "no regexp", -1);
return;
}

if( sqlite3_value_type(argv[1]) == SQLITE_NULL )
{
sqlite3_result_int(ctx, 0);
return;
}

const char *str = (const char *) sqlite3_value_text(argv[1]);
if (!str) {
sqlite3_result_error(ctx, "no string", -1);
return;
}

pcre2_code* p = re_compile_with_cache(ctx, re);
if (!p)
return;

pcre2_match_data *md = pcre2_match_data_create_from_pattern(p, nullptr);
if (!str) {
sqlite3_result_error(ctx, "could not create match data block", -1);
return;
}
int rc = pcre2_match(p, reinterpret_cast<const PCRE2_UCHAR8*>(str),
PCRE2_ZERO_TERMINATED, 0, 0, md, nullptr);
sqlite3_result_int(ctx, rc >= 0);
}


#elif defined(HAVE_PCRE)

#include <pcre.h>

Expand Down Expand Up @@ -160,12 +287,12 @@ void OGRSQLiteREGEXPFunction( sqlite3_context *ctx,

static
void* OGRSQLiteRegisterRegExpFunction(sqlite3*
#ifdef HAVE_PCRE
#if defined(HAVE_PCRE) || defined(HAVE_PCRE2)
hDB
#endif
)
{
#ifdef HAVE_PCRE
#if defined(HAVE_PCRE) || defined(HAVE_PCRE2)

/* For debugging purposes mostly */
if( !CPLTestBool(CPLGetConfigOption("OGR_SQLITE_REGEXP", "YES")) )
Expand Down Expand Up @@ -198,12 +325,24 @@ void* OGRSQLiteRegisterRegExpFunction(sqlite3*

static
void OGRSQLiteFreeRegExpCache(void*
#ifdef HAVE_PCRE
#if defined(HAVE_PCRE) || defined(HAVE_PCRE2)
hRegExpCache
#endif
)
{
#ifdef HAVE_PCRE
#ifdef HAVE_PCRE2
if( hRegExpCache == nullptr )
return;

cache_entry *cache = (cache_entry*) hRegExpCache;
for( int i = 0; i < CACHE_SIZE && cache[i].s; i++ )
{
CPLFree(cache[i].s);
CPLAssert(cache[i].p);
pcre2_code_free(cache[i].p);
}
CPLFree(cache);
#elif defined(HAVE_PCRE)
if( hRegExpCache == nullptr )
return;

Expand Down

0 comments on commit 4c187d9

Please sign in to comment.