summaryrefslogtreecommitdiffstats
path: root/debian/patches/workarounds/0005-pcre2.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/workarounds/0005-pcre2.patch')
-rw-r--r--debian/patches/workarounds/0005-pcre2.patch1219
1 files changed, 1219 insertions, 0 deletions
diff --git a/debian/patches/workarounds/0005-pcre2.patch b/debian/patches/workarounds/0005-pcre2.patch
new file mode 100644
index 0000000..7dfda8c
--- /dev/null
+++ b/debian/patches/workarounds/0005-pcre2.patch
@@ -0,0 +1,1219 @@
+Description: Port to PCRE2.
+Bug-Debian: https://bugs.debian.org/1000113
+Author: Yavor Doganov <yavor@gnu.org>
+Forwarded: no
+Last-Update: 2024-01-07
+---
+
+--- kodi-20.2+dfsg.orig/cmake/modules/FindPCRE.cmake
++++ kodi-20.2+dfsg/cmake/modules/FindPCRE.cmake
+@@ -77,45 +77,34 @@
+
+ else()
+ # Populate paths for find_package_handle_standard_args
+- find_path(PCRE_INCLUDE_DIR pcre.h)
++ find_path(PCRE_INCLUDE_DIR pcre2.h)
+
+- find_library(PCRECPP_LIBRARY_RELEASE NAMES pcrecpp)
+- find_library(PCRECPP_LIBRARY_DEBUG NAMES pcrecppd)
+-
+- find_library(PCRE_LIBRARY_RELEASE NAMES pcre)
+- find_library(PCRE_LIBRARY_DEBUG NAMES pcred)
++ find_library(PCRE_LIBRARY_RELEASE NAMES pcre2-8)
+ endif()
+ else()
+
+ if(PKG_CONFIG_FOUND)
+- pkg_check_modules(PC_PCRE libpcrecpp QUIET)
++ pkg_check_modules(PC_PCRE libpcre2-8 QUIET)
+ endif()
+
+- find_path(PCRE_INCLUDE_DIR pcrecpp.h
++ find_path(PCRE_INCLUDE_DIR pcre2.h
+ PATHS ${PC_PCRE_INCLUDEDIR})
+- find_library(PCRECPP_LIBRARY_RELEASE NAMES pcrecpp
+- PATHS ${PC_PCRE_LIBDIR})
+- find_library(PCRE_LIBRARY_RELEASE NAMES pcre
++ find_library(PCRE_LIBRARY_RELEASE NAMES pcre2-8
+ PATHS ${PC_PCRE_LIBDIR})
+- find_library(PCRECPP_LIBRARY_DEBUG NAMES pcrecppd
+- PATHS ${PC_PCRE_LIBDIR})
+- find_library(PCRE_LIBRARY_DEBUG NAMES pcred
+- PATHS ${PC_PCRE_LIBDIR})
+ set(PCRE_VERSION ${PC_PCRE_VERSION})
+
+ endif()
+
+ include(SelectLibraryConfigurations)
+- select_library_configurations(PCRECPP)
+ select_library_configurations(PCRE)
+
+ include(FindPackageHandleStandardArgs)
+ find_package_handle_standard_args(PCRE
+- REQUIRED_VARS PCRECPP_LIBRARY PCRE_LIBRARY PCRE_INCLUDE_DIR
++ REQUIRED_VARS PCRE_LIBRARY PCRE_INCLUDE_DIR
+ VERSION_VAR PCRE_VERSION)
+
+ if(PCRE_FOUND)
+- set(PCRE_LIBRARIES ${PCRECPP_LIBRARY} ${PCRE_LIBRARY})
++ set(PCRE_LIBRARIES ${PCRE_LIBRARY})
+ set(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR})
+ if(WIN32)
+ set(PCRE_DEFINITIONS -DPCRE_STATIC=1)
+@@ -166,5 +155,5 @@
+ endif()
+ endif()
+
+- mark_as_advanced(PCRE_INCLUDE_DIR PCRECPP_LIBRARY PCRE_LIBRARY)
++ mark_as_advanced(PCRE_INCLUDE_DIR PCRE_LIBRARY)
+ endif()
+--- kodi-20.2+dfsg.orig/xbmc/utils/RegExp.h
++++ kodi-20.2+dfsg/xbmc/utils/RegExp.h
+@@ -13,16 +13,8 @@
+ #include <string>
+ #include <vector>
+
+-/* make sure stdlib.h is included before including pcre.h inside the
+- namespace; this works around stdlib.h definitions also living in
+- the PCRE namespace */
+-#include <stdlib.h>
+-
+-namespace PCRE {
+-struct real_pcre_jit_stack; // forward declaration for PCRE without JIT
+-typedef struct real_pcre_jit_stack pcre_jit_stack;
+-#include <pcre.h>
+-}
++#define PCRE2_CODE_UNIT_WIDTH 8
++#include <pcre2.h>
+
+ class CRegExp
+ {
+@@ -143,17 +135,17 @@
+ void Cleanup();
+ inline bool IsValidSubNumber(int iSub) const;
+
+- PCRE::pcre* m_re;
+- PCRE::pcre_extra* m_sd;
++ pcre2_code* m_re;
++ pcre2_match_context* m_ctxt;
+ static const int OVECCOUNT=(m_MaxNumOfBackrefrences + 1) * 3;
+ unsigned int m_offset;
+- int m_iOvector[OVECCOUNT];
++ PCRE2_SIZE* m_iOvector;
+ utf8Mode m_utf8Mode;
+ int m_iMatchCount;
+- int m_iOptions;
++ uint32_t m_iOptions;
+ bool m_jitCompiled;
+ bool m_bMatched;
+- PCRE::pcre_jit_stack* m_jitStack;
++ pcre2_jit_stack* m_jitStack;
+ std::string m_subject;
+ std::string m_pattern;
+ static int m_Utf8Supported;
+--- kodi-20.2+dfsg.orig/xbmc/filesystem/FTPParse.cpp
++++ kodi-20.2+dfsg/xbmc/filesystem/FTPParse.cpp
+@@ -9,8 +9,10 @@
+ #include "FTPParse.h"
+
+ #include <cmath>
++#include <cstring>
+
+-#include <pcrecpp.h>
++#define PCRE2_CODE_UNIT_WIDTH 8
++#include <pcre2.h>
+
+ CFTPParse::CFTPParse()
+ {
+@@ -46,26 +48,31 @@
+
+ void CFTPParse::setTime(const std::string& str)
+ {
++ pcre2_code *re, *unix_re, *multinet_re, *msdos_re;
++ pcre2_match_data *md;
++ PCRE2_SPTR unix_pat, multinet_pat, msdos_pat, str_sptr;
++ PCRE2_SIZE offset;
++ int err;
+ /* Variables used to capture patterns via the regexes */
+- std::string month;
+- std::string day;
+- std::string year;
+- std::string hour;
+- std::string minute;
+- std::string second;
+- std::string am_or_pm;
++ char *month = NULL;
++ PCRE2_UCHAR *day = NULL;
++ PCRE2_UCHAR *year = NULL;
++ PCRE2_UCHAR *hour = NULL;
++ PCRE2_UCHAR *minute = NULL;
++ PCRE2_UCHAR *second = NULL;
++ PCRE2_UCHAR *am_or_pm = NULL;
+
+ /* time struct used to set the time_t variable */
+ struct tm time_struct = {};
+
+ /* Regex to read Unix, NetWare and NetPresenz time format */
+- pcrecpp::RE unix_re("^([A-Za-z]{3})" // month
++ unix_pat = reinterpret_cast<PCRE2_SPTR>("^([A-Za-z]{3})" // month
+ "\\s+(\\d{1,2})" // day of month
+ "\\s+([:\\d]{4,5})$" // time of day or year
+ );
+
+ /* Regex to read MultiNet time format */
+- pcrecpp::RE multinet_re("^(\\d{1,2})" // day of month
++ multinet_pat = reinterpret_cast<PCRE2_SPTR>("^(\\d{1,2})" // day of month
+ "-([A-Za-z]{3})" // month
+ "-(\\d{4})" // year
+ "\\s+(\\d{2})" // hour
+@@ -74,7 +81,7 @@
+ );
+
+ /* Regex to read MSDOS time format */
+- pcrecpp::RE msdos_re("^(\\d{2})" // month
++ msdos_pat = reinterpret_cast<PCRE2_SPTR>("^(\\d{2})" // month
+ "-(\\d{2})" // day of month
+ "-(\\d{2})" // year
+ "\\s+(\\d{2})" // hour
+@@ -82,48 +89,53 @@
+ "([AP]M)$" // AM or PM
+ );
+
+- if (unix_re.FullMatch(str, &month, &day, &year))
+- {
++ unix_re = pcre2_compile(unix_pat, PCRE2_ZERO_TERMINATED,
++ 0, &err, &offset, NULL);
++ multinet_re = pcre2_compile(multinet_pat, PCRE2_ZERO_TERMINATED,
++ 0, &err, &offset, NULL);
++ msdos_re = pcre2_compile(msdos_pat, PCRE2_ZERO_TERMINATED,
++ 0, &err, &offset, NULL);
++ str_sptr = reinterpret_cast<PCRE2_SPTR>(str.c_str());
++ md = pcre2_match_data_create(30, NULL);
++
++ if (pcre2_match(unix_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL)
++ > 0)
++ {
++ pcre2_substring_get_bynumber(md, 1,
++ reinterpret_cast<PCRE2_UCHAR **>(&month),
++ &offset);
++ pcre2_substring_get_bynumber(md, 2, &day, &offset);
++ pcre2_substring_get_bynumber(md, 3, &year, &offset);
++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("(\\d{2}):(\\d{2})"),
++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL);
+ /* set the month */
+- if (pcrecpp::RE("jan",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ if (strcasestr(month, "jan"))
+ time_struct.tm_mon = 0;
+- else if (pcrecpp::RE("feb",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "feb"))
+ time_struct.tm_mon = 1;
+- else if (pcrecpp::RE("mar",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "mar"))
+ time_struct.tm_mon = 2;
+- else if (pcrecpp::RE("apr",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "apr"))
+ time_struct.tm_mon = 3;
+- else if (pcrecpp::RE("may",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "may"))
+ time_struct.tm_mon = 4;
+- else if (pcrecpp::RE("jun",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "jun"))
+ time_struct.tm_mon = 5;
+- else if (pcrecpp::RE("jul",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "jul"))
+ time_struct.tm_mon = 6;
+- else if (pcrecpp::RE("aug",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "aug"))
+ time_struct.tm_mon = 7;
+- else if (pcrecpp::RE("sep",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "sep"))
+ time_struct.tm_mon = 8;
+- else if (pcrecpp::RE("oct",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "oct"))
+ time_struct.tm_mon = 9;
+- else if (pcrecpp::RE("nov",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "nov"))
+ time_struct.tm_mon = 10;
+- else if (pcrecpp::RE("dec",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "dec"))
+ time_struct.tm_mon = 11;
+
+ /* set the day of the month */
+- time_struct.tm_mday = atoi(day.c_str());
++ time_struct.tm_mday = atoi(reinterpret_cast<const char *>(day));
+
+ time_t t = time(NULL);
+ struct tm *current_time;
+@@ -133,11 +145,14 @@
+ #else
+ current_time = localtime(&t);
+ #endif
+- if (pcrecpp::RE("(\\d{2}):(\\d{2})").FullMatch(year, &hour, &minute))
++ if (pcre2_match(re, reinterpret_cast<PCRE2_SPTR>(year),
++ PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) > 0)
+ {
++ pcre2_substring_get_bynumber(md, 1, &hour, &offset);
++ pcre2_substring_get_bynumber(md, 2, &minute, &offset);
+ /* set the hour and minute */
+- time_struct.tm_hour = atoi(hour.c_str());
+- time_struct.tm_min = atoi(minute.c_str());
++ time_struct.tm_hour = atoi(reinterpret_cast<const char *>(hour));
++ time_struct.tm_min = atoi(reinterpret_cast<const char *>(minute));
+
+ /* set the year */
+ if ((current_time->tm_mon - time_struct.tm_mon < 0) ||
+@@ -150,93 +165,99 @@
+ else
+ {
+ /* set the year */
+- time_struct.tm_year = atoi(year.c_str()) - 1900;
++ time_struct.tm_year = atoi(reinterpret_cast<const char *>(year)) - 1900;
+ }
+
+ /* set the day of the week */
+ time_struct.tm_wday = getDayOfWeek(time_struct.tm_mon + 1,
+ time_struct.tm_mday,
+ time_struct.tm_year + 1900);
++ pcre2_code_free(re);
+ }
+- else if (multinet_re.FullMatch(str, &day, &month, &year,
+- &hour, &minute, (void*)NULL, &second))
++ else if (pcre2_match(multinet_re, str_sptr, PCRE2_ZERO_TERMINATED,
++ 0, 0, md, NULL) > 0)
+ {
++ pcre2_substring_get_bynumber(md, 1, &day, &offset);
++ pcre2_substring_get_bynumber(md, 2,
++ reinterpret_cast<PCRE2_UCHAR **>(&month),
++ &offset);
++ pcre2_substring_get_bynumber(md, 3, &year, &offset);
++ pcre2_substring_get_bynumber(md, 4, &hour, &offset);
++ pcre2_substring_get_bynumber(md, 5, &minute, &offset);
++ pcre2_substring_get_bynumber(md, 7, &second, &offset);
+ /* set the month */
+- if (pcrecpp::RE("jan",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ if (strcasestr(month, "jan"))
+ time_struct.tm_mon = 0;
+- else if (pcrecpp::RE("feb",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "feb"))
+ time_struct.tm_mon = 1;
+- else if (pcrecpp::RE("mar",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "mar"))
+ time_struct.tm_mon = 2;
+- else if (pcrecpp::RE("apr",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "apr"))
+ time_struct.tm_mon = 3;
+- else if (pcrecpp::RE("may",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "may"))
+ time_struct.tm_mon = 4;
+- else if (pcrecpp::RE("jun",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "jun"))
+ time_struct.tm_mon = 5;
+- else if (pcrecpp::RE("jul",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "jul"))
+ time_struct.tm_mon = 6;
+- else if (pcrecpp::RE("aug",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "aug"))
+ time_struct.tm_mon = 7;
+- else if (pcrecpp::RE("sep",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "sep"))
+ time_struct.tm_mon = 8;
+- else if (pcrecpp::RE("oct",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "oct"))
+ time_struct.tm_mon = 9;
+- else if (pcrecpp::RE("nov",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "nov"))
+ time_struct.tm_mon = 10;
+- else if (pcrecpp::RE("dec",
+- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
++ else if (strcasestr(month, "dec"))
+ time_struct.tm_mon = 11;
+
+ /* set the day of the month and year */
+- time_struct.tm_mday = atoi(day.c_str());
+- time_struct.tm_year = atoi(year.c_str()) - 1900;
++ time_struct.tm_mday = atoi(reinterpret_cast<const char *>(day));
++ time_struct.tm_year = atoi(reinterpret_cast<const char *>(year)) - 1900;
+
+ /* set the hour and minute */
+- time_struct.tm_hour = atoi(hour.c_str());
+- time_struct.tm_min = atoi(minute.c_str());
++ time_struct.tm_hour = atoi(reinterpret_cast<const char *>(hour));
++ time_struct.tm_min = atoi(reinterpret_cast<const char *>(minute));
+
+ /* set the second if given*/
+- if (second.length() > 0)
+- time_struct.tm_sec = atoi(second.c_str());
++ if (strlen(reinterpret_cast<const char *>(second)) > 0)
++ time_struct.tm_sec = atoi(reinterpret_cast<const char *>(second));
+
+ /* set the day of the week */
+ time_struct.tm_wday = getDayOfWeek(time_struct.tm_mon + 1,
+ time_struct.tm_mday,
+ time_struct.tm_year + 1900);
+ }
+- else if (msdos_re.FullMatch(str, &month, &day,
+- &year, &hour, &minute, &am_or_pm))
++ else if (pcre2_match(msdos_re, str_sptr, PCRE2_ZERO_TERMINATED,
++ 0, 0, md, NULL) > 0)
+ {
++ pcre2_substring_get_bynumber(md, 1,
++ reinterpret_cast<PCRE2_UCHAR **>(&month),
++ &offset);
++ pcre2_substring_get_bynumber(md, 2, &day, &offset);
++ pcre2_substring_get_bynumber(md, 3, &year, &offset);
++ pcre2_substring_get_bynumber(md, 4, &hour, &offset);
++ pcre2_substring_get_bynumber(md, 5, &minute, &offset);
++ pcre2_substring_get_bynumber(md, 6, &am_or_pm, &offset);
++
+ /* set the month and the day of the month */
+- time_struct.tm_mon = atoi(month.c_str()) - 1;
+- time_struct.tm_mday = atoi(day.c_str());
++ time_struct.tm_mon = atoi(month) - 1;
++ time_struct.tm_mday = atoi(reinterpret_cast<const char *>(day));
+
+ /* set the year */
+- time_struct.tm_year = atoi(year.c_str());
++ time_struct.tm_year = atoi(reinterpret_cast<const char *>(year));
+ if (time_struct.tm_year < 70)
+ time_struct.tm_year += 100;
+
+ /* set the hour */
+- time_struct.tm_hour = atoi(hour.c_str());
++ time_struct.tm_hour = atoi(reinterpret_cast<const char *>(hour));
+ if (time_struct.tm_hour == 12)
+ time_struct.tm_hour -= 12;
+- if (pcrecpp::RE("PM").FullMatch(am_or_pm))
++ if (strstr(reinterpret_cast<const char *>(am_or_pm), "PM"))
+ time_struct.tm_hour += 12;
+
+ /* set the minute */
+- time_struct.tm_min = atoi(minute.c_str());
++ time_struct.tm_min = atoi(reinterpret_cast<const char *>(minute));
+
+ /* set the day of the week */
+ time_struct.tm_wday = getDayOfWeek(time_struct.tm_mon + 1,
+@@ -246,6 +267,18 @@
+
+ /* now set m_time */
+ m_time = mktime(&time_struct);
++
++ pcre2_code_free(unix_re);
++ pcre2_code_free(multinet_re);
++ pcre2_code_free(msdos_re);
++ pcre2_match_data_free(md);
++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(month));
++ pcre2_substring_free(day);
++ pcre2_substring_free(year);
++ pcre2_substring_free(hour);
++ pcre2_substring_free(minute);
++ pcre2_substring_free(second);
++ pcre2_substring_free(am_or_pm);
+ }
+
+ int CFTPParse::getDayOfWeek(int month, int date, int year)
+@@ -325,22 +358,22 @@
+
+ int CFTPParse::FTPParse(const std::string& str)
+ {
++ pcre2_code *unix_re, *netware_re, *netpresenz_re, *eplf_re, *multinet_re,
++ *msdos_re;
++ pcre2_match_data *md;
++ PCRE2_SPTR unix_pat, netware_pat, netpresenz_pat, eplf_pat, multinet_pat,
++ msdos_pat, str_sptr;
++ PCRE2_SIZE offset;
++ int err;
+ /* Various variable to capture patterns via the regexes */
+- std::string permissions;
+- std::string link_count;
+- std::string owner;
+- std::string group;
+- std::string size;
+- std::string date;
+- std::string name;
+- std::string type;
+- std::string stuff;
+- std::string facts;
+- std::string version;
+- std::string file_id;
++ char *type = NULL;
++ PCRE2_UCHAR *size = NULL;
++ PCRE2_UCHAR *date = NULL;
++ PCRE2_UCHAR *name = NULL;
++ PCRE2_UCHAR *facts;
+
+ /* Regex for standard Unix listing formats */
+- pcrecpp::RE unix_re("^([-bcdlps])" // type
++ unix_pat = reinterpret_cast<PCRE2_SPTR>("^([-bcdlps])" // type
+ "([-rwxXsStT]{9})" // permissions
+ "\\s+(\\d+)" // hard link count
+ "\\s+(\\w+)" // owner
+@@ -352,7 +385,7 @@
+
+ /* Regex for NetWare listing formats */
+ /* See http://www.novell.com/documentation/oes/ftp_enu/data/a3ep22p.html#fbhbaijf */
+- pcrecpp::RE netware_re("^([-d])" // type
++ netware_pat = reinterpret_cast<PCRE2_SPTR>("^([-d])" // type
+ "\\s+(\\[[-SRWCIEMFA]{8}\\])" // rights
+ "\\s+(\\w+)" // owner
+ "\\s+(\\d+)" // size
+@@ -363,7 +396,7 @@
+ /* Regex for NetPresenz */
+ /* See http://files.stairways.com/other/ftp-list-specs-info.txt */
+ /* Here we will capture permissions and size if given */
+- pcrecpp::RE netpresenz_re("^([-dl])" // type
++ netpresenz_pat = reinterpret_cast<PCRE2_SPTR>("^([-dl])" // type
+ "([-rwx]{9}|)" // permissions
+ "\\s+(.*)" // stuff
+ "\\s+(\\d+|)" // size
+@@ -374,7 +407,7 @@
+ /* Regex for EPLF */
+ /* See http://cr.yp.to/ftp/list/eplf.html */
+ /* SAVE: "(/,|r,|s\\d+,|m\\d+,|i[\\d!#@$%^&*()]+(\\.[\\d!#@$%^&*()]+|),)+" */
+- pcrecpp::RE eplf_re("^\\+" // initial "plus" sign
++ eplf_pat = reinterpret_cast<PCRE2_SPTR>("^\\+" // initial "plus" sign
+ "([^\\s]+)" // facts
+ "\\s(.+)$" // name
+ );
+@@ -382,7 +415,7 @@
+ /* Regex for MultiNet */
+ /* Best documentation found was
+ * http://www-sld.slac.stanford.edu/SLDWWW/workbook/vms_files.html */
+- pcrecpp::RE multinet_re("^([^;]+)" // name
++ multinet_pat = reinterpret_cast<PCRE2_SPTR>("^([^;]+)" // name
+ ";(\\d+)" // version
+ "\\s+([\\d/]+)" // file id
+ "\\s+(\\d{1,2}-[A-Za-z]{3}-\\d{4}\\s+\\d{2}:\\d{2}(:\\d{2})?)" // date
+@@ -391,20 +424,42 @@
+ );
+
+ /* Regex for MSDOS */
+- pcrecpp::RE msdos_re("^(\\d{2}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}[AP]M)" // date
++ msdos_pat = reinterpret_cast<PCRE2_SPTR>("^(\\d{2}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}[AP]M)" // date
+ "\\s+(<DIR>|[\\d]+)" // dir or size
+ "\\s+(.+)$" // name
+ );
+
+- if (unix_re.FullMatch(str, &type, &permissions, &link_count, &owner, &group, &size, &date, &name))
+- {
+- m_name = name;
+- m_size = (uint64_t)strtod(size.c_str(), NULL);
+- if (pcrecpp::RE("d").FullMatch(type))
++ unix_re = pcre2_compile(unix_pat, PCRE2_ZERO_TERMINATED,
++ 0, &err, &offset, NULL);
++ netware_re = pcre2_compile(netware_pat, PCRE2_ZERO_TERMINATED,
++ 0, &err, &offset, NULL);
++ netpresenz_re = pcre2_compile(netpresenz_pat, PCRE2_ZERO_TERMINATED,
++ 0, &err, &offset, NULL);
++ eplf_re = pcre2_compile(eplf_pat, PCRE2_ZERO_TERMINATED,
++ 0, &err, &offset, NULL);
++ multinet_re = pcre2_compile(multinet_pat, PCRE2_ZERO_TERMINATED,
++ 0, &err, &offset, NULL);
++ msdos_re = pcre2_compile(msdos_pat, PCRE2_ZERO_TERMINATED,
++ 0, &err, &offset, NULL);
++ md = pcre2_match_data_create(30, NULL);
++ str_sptr = reinterpret_cast<PCRE2_SPTR>(str.c_str());
++
++ if (pcre2_match(unix_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL)
++ > 0)
++ {
++ pcre2_substring_get_bynumber(md, 1,
++ reinterpret_cast<PCRE2_UCHAR **>(&type),
++ &offset);
++ pcre2_substring_get_bynumber(md, 6, &size, &offset);
++ pcre2_substring_get_bynumber(md, 7, &date, &offset);
++ pcre2_substring_get_bynumber(md, 8, &name, &offset);
++ m_name = reinterpret_cast<const char *>(name);
++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL);
++ if (strstr(type, "d"))
+ m_flagtrycwd = 1;
+- if (pcrecpp::RE("-").FullMatch(type))
++ if (strstr(type, "-"))
+ m_flagtryretr = 1;
+- if (pcrecpp::RE("l").FullMatch(type))
++ if (strstr(type, "l"))
+ {
+ m_flagtrycwd = m_flagtryretr = 1;
+ // handle symlink
+@@ -412,31 +467,67 @@
+ if (found != std::string::npos)
+ m_name = m_name.substr(0, found);
+ }
+- setTime(date);
++ setTime(reinterpret_cast<const char *>(date));
++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(type));
++ pcre2_substring_free(size);
++ pcre2_substring_free(date);
++ pcre2_substring_free(name);
++ pcre2_match_data_free(md);
++ pcre2_code_free(unix_re);
++ pcre2_code_free(netware_re);
++ pcre2_code_free(netpresenz_re);
++ pcre2_code_free(eplf_re);
++ pcre2_code_free(multinet_re);
++ pcre2_code_free(msdos_re);
+
+ return 1;
+ }
+- if (netware_re.FullMatch(str, &type, &permissions, &owner, &size, &date, &name))
++ if (pcre2_match(netware_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL)
++ > 0)
+ {
+- m_name = name;
+- m_size = (uint64_t)strtod(size.c_str(), NULL);
+- if (pcrecpp::RE("d").FullMatch(type))
++ pcre2_substring_get_bynumber(md, 1,
++ reinterpret_cast<PCRE2_UCHAR **>(&type),
++ &offset);
++ pcre2_substring_get_bynumber(md, 4, &size, &offset);
++ pcre2_substring_get_bynumber(md, 5, &date, &offset);
++ pcre2_substring_get_bynumber(md, 6, &name, &offset);
++ m_name = reinterpret_cast<const char *>(name);
++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL);
++ if (strstr(type, "d"))
+ m_flagtrycwd = 1;
+- if (pcrecpp::RE("-").FullMatch(type))
++ if (strstr(type, "-"))
+ m_flagtryretr = 1;
+- setTime(date);
++ setTime(reinterpret_cast<const char *>(date));
++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(type));
++ pcre2_substring_free(size);
++ pcre2_substring_free(date);
++ pcre2_substring_free(name);
++ pcre2_match_data_free(md);
++ pcre2_code_free(unix_re);
++ pcre2_code_free(netware_re);
++ pcre2_code_free(netpresenz_re);
++ pcre2_code_free(eplf_re);
++ pcre2_code_free(multinet_re);
++ pcre2_code_free(msdos_re);
+
+ return 1;
+ }
+- if (netpresenz_re.FullMatch(str, &type, &permissions, &stuff, &size, &date, &name))
++ if (pcre2_match(netpresenz_re, str_sptr, PCRE2_ZERO_TERMINATED,
++ 0, 0, md, NULL) > 0)
+ {
+- m_name = name;
+- m_size = (uint64_t)strtod(size.c_str(), NULL);
+- if (pcrecpp::RE("d").FullMatch(type))
++ pcre2_substring_get_bynumber(md, 1,
++ reinterpret_cast<PCRE2_UCHAR **>(&type),
++ &offset);
++ pcre2_substring_get_bynumber(md, 4, &size, &offset);
++ pcre2_substring_get_bynumber(md, 5, &date, &offset);
++ pcre2_substring_get_bynumber(md, 6, &name, &offset);
++ m_name = reinterpret_cast<const char *>(name);
++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL);
++ if (strstr(type, "d"))
+ m_flagtrycwd = 1;
+- if (pcrecpp::RE("-").FullMatch(type))
++ if (strstr(type, "-"))
+ m_flagtryretr = 1;
+- if (pcrecpp::RE("l").FullMatch(type))
++ if (strstr(type, "l"))
+ {
+ m_flagtrycwd = m_flagtryretr = 1;
+ // handle symlink
+@@ -444,48 +535,118 @@
+ if (found != std::string::npos)
+ m_name = m_name.substr(0, found);
+ }
+- setTime(date);
++ setTime(reinterpret_cast<const char *>(date));
++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(type));
++ pcre2_substring_free(size);
++ pcre2_substring_free(date);
++ pcre2_substring_free(name);
++ pcre2_match_data_free(md);
++ pcre2_code_free(unix_re);
++ pcre2_code_free(netware_re);
++ pcre2_code_free(netpresenz_re);
++ pcre2_code_free(eplf_re);
++ pcre2_code_free(multinet_re);
++ pcre2_code_free(msdos_re);
+
+ return 1;
+ }
+- if (eplf_re.FullMatch(str, &facts, &name))
++ if (pcre2_match(eplf_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL)
++ > 0)
+ {
++ pcre2_code *re;
++
++ pcre2_substring_get_bynumber(md, 1, &facts, &offset);
++ pcre2_substring_get_bynumber(md, 2, &name, &offset);
+ /* Get the type, size, and date from the facts */
+- pcrecpp::RE("(\\+|,)(r|/),").PartialMatch(facts, (void*)NULL, &type);
+- pcrecpp::RE("(\\+|,)s(\\d+),").PartialMatch(facts, (void*)NULL, &size);
+- pcrecpp::RE("(\\+|,)m(\\d+),").PartialMatch(facts, (void*)NULL, &date);
+-
+- m_name = name;
+- m_size = (uint64_t)strtod(size.c_str(), NULL);
+- if (pcrecpp::RE("/").FullMatch(type))
++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("(\\+|,)(r|/),"),
++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL);
++ if (pcre2_match(re, facts, PCRE2_ZERO_TERMINATED, 0,
++ PCRE2_PARTIAL_SOFT, md, NULL) > 0)
++ pcre2_substring_get_bynumber(md, 2,
++ reinterpret_cast<PCRE2_UCHAR **>(&type),
++ &offset);
++ pcre2_code_free(re);
++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("(\\+|,)s(\\d+),"),
++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL);
++ if (pcre2_match(re, facts, PCRE2_ZERO_TERMINATED, 0,
++ PCRE2_PARTIAL_SOFT, md, NULL) > 0)
++ pcre2_substring_get_bynumber(md, 2, &size, &offset);
++ pcre2_code_free(re);
++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("(\\+|,)m(\\d+),"),
++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL);
++ if (pcre2_match(re, facts, PCRE2_ZERO_TERMINATED, 0,
++ PCRE2_PARTIAL_SOFT, md, NULL) > 0)
++ pcre2_substring_get_bynumber(md, 2, &date, &offset);
++ pcre2_code_free(re);
++ pcre2_substring_free(facts);
++
++ m_name = reinterpret_cast<const char *>(name);
++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL);
++ if (strstr(type, "/"))
+ m_flagtrycwd = 1;
+- if (pcrecpp::RE("r").FullMatch(type))
++ if (strstr(type, "r"))
+ m_flagtryretr = 1;
+ /* eplf stores the date in time_t format already */
+- m_time = atoi(date.c_str());
++ m_time = atoi(reinterpret_cast<const char *>(date));
++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(type));
++ pcre2_substring_free(size);
++ pcre2_substring_free(date);
++ pcre2_substring_free(name);
++ pcre2_match_data_free(md);
++ pcre2_code_free(unix_re);
++ pcre2_code_free(netware_re);
++ pcre2_code_free(netpresenz_re);
++ pcre2_code_free(eplf_re);
++ pcre2_code_free(multinet_re);
++ pcre2_code_free(msdos_re);
+
+ return 1;
+ }
+- if (multinet_re.FullMatch(str, &name, &version, &file_id, &date, (void*)NULL, &owner, &permissions))
++ if (pcre2_match(multinet_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL)
++ > 0)
+ {
+- if (pcrecpp::RE("\\.DIR$").PartialMatch(name))
++ pcre2_code *re;
++ std::string tmp;
++
++ pcre2_substring_get_bynumber(md, 1, &name, &offset);
++ pcre2_substring_get_bynumber(md, 4, &date, &offset);
++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("\\.DIR$"),
++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL);
++ //if (pcrecpp::RE("\\.DIR$").PartialMatch(name))
++ tmp = reinterpret_cast<const char *>(name);
++ if (pcre2_match(re, name, PCRE2_ZERO_TERMINATED, 0, PCRE2_PARTIAL_SOFT,
++ md, NULL) > 0)
+ {
+- name.resize(name.size() - 4);
++ tmp.resize(tmp.size() - 4);
+ m_flagtrycwd = 1;
+ }
+ else
+ m_flagtryretr = 1;
+- m_name = name;
+- setTime(date);
++ m_name = tmp;
++ setTime(reinterpret_cast<const char *>(date));
+ /* Multinet doesn't provide a size */
+ m_size = 0;
++ pcre2_substring_free(date);
++ pcre2_substring_free(name);
++ pcre2_match_data_free(md);
++ pcre2_code_free(re);
++ pcre2_code_free(unix_re);
++ pcre2_code_free(netware_re);
++ pcre2_code_free(netpresenz_re);
++ pcre2_code_free(eplf_re);
++ pcre2_code_free(multinet_re);
++ pcre2_code_free(msdos_re);
+
+ return 1;
+ }
+- if (msdos_re.FullMatch(str, &date, &size, &name))
++ if (pcre2_match(msdos_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL)
++ > 0)
+ {
+- m_name = name;
+- if (pcrecpp::RE("<DIR>").FullMatch(size))
++ pcre2_substring_get_bynumber(md, 1, &date, &offset);
++ pcre2_substring_get_bynumber(md, 2, &size, &offset);
++ pcre2_substring_get_bynumber(md, 3, &name, &offset);
++ m_name = reinterpret_cast<const char *>(name);
++ if (strstr(reinterpret_cast<const char *>(size), "<DIR>"))
+ {
+ m_flagtrycwd = 1;
+ m_size = 0;
+@@ -493,12 +654,29 @@
+ else
+ {
+ m_flagtryretr = 1;
+- m_size = (uint64_t)strtod(size.c_str(), NULL);
++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL);
+ }
+- setTime(date);
++ setTime(reinterpret_cast<const char *>(date));
++ pcre2_substring_free(date);
++ pcre2_substring_free(size);
++ pcre2_substring_free(name);
++ pcre2_match_data_free(md);
++ pcre2_code_free(unix_re);
++ pcre2_code_free(netware_re);
++ pcre2_code_free(netpresenz_re);
++ pcre2_code_free(eplf_re);
++ pcre2_code_free(multinet_re);
++ pcre2_code_free(msdos_re);
+
+ return 1;
+ }
++ pcre2_match_data_free(md);
++ pcre2_code_free(unix_re);
++ pcre2_code_free(netware_re);
++ pcre2_code_free(netpresenz_re);
++ pcre2_code_free(eplf_re);
++ pcre2_code_free(multinet_re);
++ pcre2_code_free(msdos_re);
+
+ return 0;
+ }
+--- kodi-20.2+dfsg.orig/xbmc/utils/RegExp.cpp
++++ kodi-20.2+dfsg/xbmc/utils/RegExp.cpp
+@@ -16,27 +16,6 @@
+ #include <stdlib.h>
+ #include <string.h>
+
+-using namespace PCRE;
+-
+-#ifndef PCRE_UCP
+-#define PCRE_UCP 0
+-#endif // PCRE_UCP
+-
+-#ifdef PCRE_CONFIG_JIT
+-#define PCRE_HAS_JIT_CODE 1
+-#endif
+-
+-#ifndef PCRE_STUDY_JIT_COMPILE
+-#define PCRE_STUDY_JIT_COMPILE 0
+-#endif
+-#ifndef PCRE_INFO_JIT
+-// some unused number
+-#define PCRE_INFO_JIT 2048
+-#endif
+-#ifndef PCRE_HAS_JIT_CODE
+-#define pcre_free_study(x) pcre_free((x))
+-#endif
+-
+ int CRegExp::m_Utf8Supported = -1;
+ int CRegExp::m_UcpSupported = -1;
+ int CRegExp::m_JitSupported = -1;
+@@ -51,25 +30,24 @@
+ {
+ m_utf8Mode = utf8;
+ m_re = NULL;
+- m_sd = NULL;
+- m_iOptions = PCRE_DOTALL | PCRE_NEWLINE_ANY;
++ m_ctxt = NULL;
++ m_iOptions = PCRE2_DOTALL;
+ if(caseless)
+- m_iOptions |= PCRE_CASELESS;
++ m_iOptions |= PCRE2_CASELESS;
+ if (m_utf8Mode == forceUtf8)
+ {
+ if (IsUtf8Supported())
+- m_iOptions |= PCRE_UTF8;
++ m_iOptions |= PCRE2_UTF;
+ if (AreUnicodePropertiesSupported())
+- m_iOptions |= PCRE_UCP;
++ m_iOptions |= PCRE2_UCP;
+ }
+
+ m_offset = 0;
+ m_jitCompiled = false;
+ m_bMatched = false;
+ m_iMatchCount = 0;
++ m_iOvector = NULL;
+ m_jitStack = NULL;
+-
+- memset(m_iOvector, 0, sizeof(m_iOvector));
+ }
+
+ CRegExp::CRegExp(bool caseless, CRegExp::utf8Mode utf8, const char *re, studyMode study /*= NoStudy*/)
+@@ -225,7 +203,8 @@
+ CRegExp::CRegExp(const CRegExp& re)
+ {
+ m_re = NULL;
+- m_sd = NULL;
++ m_ctxt = NULL;
++ m_iOvector = NULL;
+ m_jitStack = NULL;
+ m_utf8Mode = re.m_utf8Mode;
+ m_iOptions = re.m_iOptions;
+@@ -240,12 +219,13 @@
+ m_pattern = re.m_pattern;
+ if (re.m_re)
+ {
+- if (pcre_fullinfo(re.m_re, NULL, PCRE_INFO_SIZE, &size) >= 0)
++ if (pcre2_pattern_info(re.m_re, PCRE2_INFO_SIZE, &size) >= 0)
+ {
+- if ((m_re = (pcre*)malloc(size)))
++ if ((m_re = pcre2_code_copy(re.m_re)))
+ {
+- memcpy(m_re, re.m_re, size);
+- memcpy(m_iOvector, re.m_iOvector, OVECCOUNT*sizeof(int));
++ if (re.m_ctxt)
++ m_ctxt = pcre2_match_context_copy(re.m_ctxt);
++ m_iOvector = re.m_iOvector;
+ m_offset = re.m_offset;
+ m_iMatchCount = re.m_iMatchCount;
+ m_bMatched = re.m_bMatched;
+@@ -273,18 +253,28 @@
+ m_jitCompiled = false;
+ m_bMatched = false;
+ m_iMatchCount = 0;
+- const char *errMsg = NULL;
+- int errOffset = 0;
+- int options = m_iOptions;
++ pcre2_compile_context *ctxt;
++ int errCode;
++ char errMsg[120];
++ PCRE2_SIZE errOffset;
++ uint32_t options = m_iOptions;
+ if (m_utf8Mode == autoUtf8 && requireUtf8(re))
+- options |= (IsUtf8Supported() ? PCRE_UTF8 : 0) | (AreUnicodePropertiesSupported() ? PCRE_UCP : 0);
++ options |= (IsUtf8Supported() ? PCRE2_UTF : 0) | (AreUnicodePropertiesSupported() ? PCRE2_UCP : 0);
+
+ Cleanup();
+
+- m_re = pcre_compile(re, options, &errMsg, &errOffset, NULL);
++ ctxt = pcre2_compile_context_create(NULL);
++ pcre2_set_newline(ctxt, PCRE2_NEWLINE_ANY);
++ m_re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>(re),
++ PCRE2_ZERO_TERMINATED, options,
++ &errCode, &errOffset, ctxt);
++ pcre2_compile_context_free(ctxt);
++
+ if (!m_re)
+ {
+ m_pattern.clear();
++ pcre2_get_error_message(errCode, reinterpret_cast<PCRE2_UCHAR *>(errMsg),
++ sizeof(errMsg));
+ CLog::Log(LOGERROR, "PCRE: {}. Compilation failed at offset {} in expression '{}'", errMsg,
+ errOffset, re);
+ return false;
+@@ -295,23 +285,12 @@
+ if (study)
+ {
+ const bool jitCompile = (study == StudyWithJitComp) && IsJitSupported();
+- const int studyOptions = jitCompile ? PCRE_STUDY_JIT_COMPILE : 0;
+
+- m_sd = pcre_study(m_re, studyOptions, &errMsg);
+- if (errMsg != NULL)
+- {
+- CLog::Log(LOGWARNING, "{}: PCRE error \"{}\" while studying expression", __FUNCTION__,
+- errMsg);
+- if (m_sd != NULL)
+- {
+- pcre_free_study(m_sd);
+- m_sd = NULL;
+- }
+- }
+- else if (jitCompile)
++ if (jitCompile)
+ {
+- int jitPresent = 0;
+- m_jitCompiled = (pcre_fullinfo(m_re, m_sd, PCRE_INFO_JIT, &jitPresent) == 0 && jitPresent == 1);
++ pcre2_jit_compile(m_re, PCRE2_JIT_COMPLETE);
++ size_t jitPresent = 0;
++ m_jitCompiled = (pcre2_pattern_info(m_re, PCRE2_INFO_JITSIZE, &jitPresent) == 0 && jitPresent > 0);
+ }
+ }
+
+@@ -325,6 +304,9 @@
+
+ int CRegExp::PrivateRegFind(size_t bufferLen, const char *str, unsigned int startoffset /* = 0*/, int maxNumberOfCharsToTest /*= -1*/)
+ {
++ pcre2_match_data *md;
++ PCRE2_SIZE offset;
++
+ m_offset = 0;
+ m_bMatched = false;
+ m_iMatchCount = 0;
+@@ -347,37 +329,47 @@
+ return -1;
+ }
+
+-#ifdef PCRE_HAS_JIT_CODE
++ if (!m_ctxt)
++ m_ctxt = pcre2_match_context_create(NULL);
++
+ if (m_jitCompiled && !m_jitStack)
+ {
+- m_jitStack = pcre_jit_stack_alloc(32*1024, 512*1024);
++ m_jitStack = pcre2_jit_stack_create(32*1024, 512*1024, NULL);
+ if (m_jitStack == NULL)
+ CLog::Log(LOGWARNING, "{}: can't allocate address space for JIT stack", __FUNCTION__);
+
+- pcre_assign_jit_stack(m_sd, NULL, m_jitStack);
++ pcre2_jit_stack_assign(m_ctxt, NULL, m_jitStack);
+ }
+-#endif
+
+ if (maxNumberOfCharsToTest >= 0)
+ bufferLen = std::min<size_t>(bufferLen, startoffset + maxNumberOfCharsToTest);
+
+ m_subject.assign(str + startoffset, bufferLen - startoffset);
+- int rc = pcre_exec(m_re, NULL, m_subject.c_str(), m_subject.length(), 0, 0, m_iOvector, OVECCOUNT);
++ md = pcre2_match_data_create(OVECCOUNT, NULL);
++ int rc = pcre2_match(m_re,
++ reinterpret_cast<PCRE2_SPTR>(m_subject.c_str()),
++ m_subject.length(), 0, 0, md, m_ctxt);
++ m_iOvector = pcre2_get_ovector_pointer(md);
++ offset = pcre2_get_startchar(md);
++ pcre2_match_data_free(md);
+
+ if (rc<1)
+ {
+ static const int fragmentLen = 80; // length of excerpt before erroneous char for log
+ switch(rc)
+ {
+- case PCRE_ERROR_NOMATCH:
++ case PCRE2_ERROR_NOMATCH:
+ return -1;
+
+- case PCRE_ERROR_MATCHLIMIT:
++ case PCRE2_ERROR_MATCHLIMIT:
+ CLog::Log(LOGERROR, "PCRE: Match limit reached");
+ return -1;
+
+-#ifdef PCRE_ERROR_SHORTUTF8
+- case PCRE_ERROR_SHORTUTF8:
++ case PCRE2_ERROR_UTF8_ERR1:
++ case PCRE2_ERROR_UTF8_ERR2:
++ case PCRE2_ERROR_UTF8_ERR3:
++ case PCRE2_ERROR_UTF8_ERR4:
++ case PCRE2_ERROR_UTF8_ERR5:
+ {
+ const size_t startPos = (m_subject.length() > fragmentLen) ? CUtf8Utils::RFindValidUtf8Char(m_subject, m_subject.length() - fragmentLen) : 0;
+ if (startPos != std::string::npos)
+@@ -389,22 +381,41 @@
+ CLog::Log(LOGERROR, "PCRE: Bad UTF-8 character at the end of string");
+ return -1;
+ }
+-#endif
+- case PCRE_ERROR_BADUTF8:
++ case PCRE2_ERROR_UTF8_ERR6:
++ case PCRE2_ERROR_UTF8_ERR7:
++ case PCRE2_ERROR_UTF8_ERR8:
++ case PCRE2_ERROR_UTF8_ERR9:
++ case PCRE2_ERROR_UTF8_ERR10:
++ case PCRE2_ERROR_UTF8_ERR11:
++ case PCRE2_ERROR_UTF8_ERR12:
++ case PCRE2_ERROR_UTF8_ERR13:
++ case PCRE2_ERROR_UTF8_ERR14:
++ case PCRE2_ERROR_UTF8_ERR15:
++ case PCRE2_ERROR_UTF8_ERR16:
++ case PCRE2_ERROR_UTF8_ERR17:
++ case PCRE2_ERROR_UTF8_ERR18:
++ case PCRE2_ERROR_UTF8_ERR19:
++ case PCRE2_ERROR_UTF8_ERR20:
++ case PCRE2_ERROR_UTF8_ERR21:
+ {
++ char errbuf[120];
++
++ pcre2_get_error_message(rc,
++ reinterpret_cast<PCRE2_UCHAR *>(errbuf),
++ sizeof(errbuf));
+ const size_t startPos = (m_iOvector[0] > fragmentLen) ? CUtf8Utils::RFindValidUtf8Char(m_subject, m_iOvector[0] - fragmentLen) : 0;
+- if (m_iOvector[0] >= 0 && startPos != std::string::npos)
++ if ((int)m_iOvector[0] >= 0 && startPos != std::string::npos)
+ CLog::Log(LOGERROR,
+ "PCRE: Bad UTF-8 character, error code: {}, position: {}. Text before bad "
+ "char: \"{}\"",
+- m_iOvector[1], m_iOvector[0],
++ errbuf, offset,
+ m_subject.substr(startPos, m_iOvector[0] - startPos + 1));
+ else
+ CLog::Log(LOGERROR, "PCRE: Bad UTF-8 character, error code: {}, position: {}",
+- m_iOvector[1], m_iOvector[0]);
++ errbuf, offset);
+ return -1;
+ }
+- case PCRE_ERROR_BADUTF8_OFFSET:
++ case PCRE2_ERROR_BADUTFOFFSET:
+ CLog::Log(LOGERROR, "PCRE: Offset is pointing to the middle of UTF-8 character");
+ return -1;
+
+@@ -423,7 +434,7 @@
+ {
+ int c = -1;
+ if (m_re)
+- pcre_fullinfo(m_re, NULL, PCRE_INFO_CAPTURECOUNT, &c);
++ pcre2_pattern_info(m_re, PCRE2_INFO_CAPTURECOUNT, &c);
+ return c;
+ }
+
+@@ -524,7 +535,7 @@
+ bool CRegExp::GetNamedSubPattern(const char* strName, std::string& strMatch) const
+ {
+ strMatch.clear();
+- int iSub = pcre_get_stringnumber(m_re, strName);
++ int iSub = pcre2_substring_number_from_name(m_re, reinterpret_cast<PCRE2_SPTR>(strName));
+ if (!IsValidSubNumber(iSub))
+ return false;
+ strMatch = GetMatch(iSub);
+@@ -533,7 +544,7 @@
+
+ int CRegExp::GetNamedSubPatternNumber(const char* strName) const
+ {
+- return pcre_get_stringnumber(m_re, strName);
++ return pcre2_substring_number_from_name(m_re, reinterpret_cast<PCRE2_SPTR>(strName));
+ }
+
+ void CRegExp::DumpOvector(int iLog /* = LOGDEBUG */)
+@@ -558,23 +569,21 @@
+ {
+ if (m_re)
+ {
+- pcre_free(m_re);
++ pcre2_code_free(m_re);
+ m_re = NULL;
+ }
+
+- if (m_sd)
++ if (m_ctxt)
+ {
+- pcre_free_study(m_sd);
+- m_sd = NULL;
++ pcre2_match_context_free(m_ctxt);
++ m_ctxt = NULL;
+ }
+
+-#ifdef PCRE_HAS_JIT_CODE
+ if (m_jitStack)
+ {
+- pcre_jit_stack_free(m_jitStack);
++ pcre2_jit_stack_free(m_jitStack);
+ m_jitStack = NULL;
+ }
+-#endif
+ }
+
+ inline bool CRegExp::IsValidSubNumber(int iSub) const
+@@ -587,7 +596,7 @@
+ {
+ if (m_Utf8Supported == -1)
+ {
+- if (pcre_config(PCRE_CONFIG_UTF8, &m_Utf8Supported) != 0)
++ if (pcre2_config(PCRE2_CONFIG_UNICODE, &m_Utf8Supported) < 0)
+ m_Utf8Supported = 0;
+ }
+
+@@ -596,13 +605,11 @@
+
+ bool CRegExp::AreUnicodePropertiesSupported(void)
+ {
+-#if defined(PCRE_CONFIG_UNICODE_PROPERTIES) && PCRE_UCP != 0
+ if (m_UcpSupported == -1)
+ {
+- if (pcre_config(PCRE_CONFIG_UNICODE_PROPERTIES, &m_UcpSupported) != 0)
++ if (pcre2_config(PCRE2_CONFIG_UNICODE, &m_UcpSupported) < 0)
+ m_UcpSupported = 0;
+ }
+-#endif
+
+ return m_UcpSupported == 1;
+ }
+@@ -625,13 +632,13 @@
+
+ if (!utf8FullSupport)
+ {
++ char ver[24];
++
++ pcre2_config(PCRE2_CONFIG_VERSION, ver);
+ CLog::Log(LOGINFO,
+- "Consider installing PCRE lib version 8.10 or later with enabled Unicode properties "
++ "Consider installing PCRE lib version 10.10 or later with enabled Unicode properties "
+ "and UTF-8 support. Your PCRE lib version: {}",
+- PCRE::pcre_version());
+-#if PCRE_UCP == 0
+- CLog::Log(LOGINFO, "You will need to rebuild XBMC after PCRE lib update.");
+-#endif
++ ver);
+ }
+
+ return utf8FullSupport;
+@@ -641,9 +648,7 @@
+ {
+ if (m_JitSupported == -1)
+ {
+-#ifdef PCRE_HAS_JIT_CODE
+- if (pcre_config(PCRE_CONFIG_JIT, &m_JitSupported) != 0)
+-#endif
++ if (pcre2_config(PCRE2_CONFIG_JIT, &m_JitSupported) < 0)
+ m_JitSupported = 0;
+ }
+
+--- kodi-20.2+dfsg.orig/xbmc/utils/test/TestRegExp.cpp
++++ kodi-20.2+dfsg/xbmc/utils/test/TestRegExp.cpp
+@@ -30,6 +30,29 @@
+ EXPECT_EQ(-1, regex.RegFind("Test string."));
+ }
+
++TEST(TestRegExp, InvalidPattern)
++{
++ CRegExp regex;
++
++ EXPECT_FALSE(regex.RegComp("+"));
++}
++
++TEST(TestRegExp, Unicode)
++{
++ CRegExp regex;
++
++ EXPECT_TRUE(regex.RegComp("Бог!$"));
++ EXPECT_EQ(12, regex.RegFind("С нами Бог!"));
++}
++
++TEST(TestRegExp, JIT)
++{
++ CRegExp regex;
++
++ EXPECT_TRUE(regex.RegComp(".JIT.", CRegExp::StudyWithJitComp));
++ EXPECT_EQ(12, regex.RegFind("Test string, JIT-matched."));
++}
++
+ TEST(TestRegExp, GetReplaceString)
+ {
+ CRegExp regex;