diff options
Diffstat (limited to 'debian/patches/workarounds/0005-pcre2.patch')
-rw-r--r-- | debian/patches/workarounds/0005-pcre2.patch | 1219 |
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; |