bool run(String string,int pos,int len) { #ifdef HX_SMART_STRINGS if (string.isUTF16Encoded()) { if (!rUtf16) { const char *error = 0; int err_offset = 0; hx::strbuf buf; rUtf16 = pcre16_compile((PCRE_SPTR16)expr.wc_str(&buf),flags|PCRE_UTF16,&error,&err_offset,NULL); if (!rUtf16) { return false; } } int n = pcre16_exec(rUtf16,NULL,(const unsigned short *)string.raw_wptr(),pos+len,pos,0,matchs,nmatchs * 3); return n>=0; } if (!rUtf8) { rUtf8 = pcre_compile(expr.utf8_str(),flags|PCRE_UTF8,0,0,0); if (!rUtf8) return false; } #endif return pcre_exec(rUtf8,NULL,string.utf8_str(),pos+len,pos,0,matchs,nmatchs * 3) >= 0; }
int regcomp(regex_t *preg, MCStringRef pattern, int cflags) { const char *errorptr; int erroffset; int options = 0; if ((cflags & REG_ICASE) != 0) options |= PCRE_CASELESS; if ((cflags & REG_NEWLINE) != 0) options |= PCRE_MULTILINE; // AL-2014-08-20: [[ Bug 13186 ]] Ensure pattern string doesn't get permanently converted to UTF-16 MCAutoStringRef t_temp; /* UNCHECKED */ MCStringMutableCopy(pattern, &t_temp); // SN-2014-01-14: [[ libpcre update ]] preg->re_pcre = pcre16_compile((PCRE_SPTR16)MCStringGetCharPtr(*t_temp), options, &errorptr, &erroffset, NULL); preg->re_erroffset = erroffset; if (preg->re_pcre == NULL) return eint[erroffset]; // [[ libpcre udpate ]] SN-2014-01-10: pcre_info() is deprecated, must be replaced with pcre_fullinfo() return pcre16_fullinfo((const pcre16 *)preg->re_pcre, NULL, PCRE_INFO_CAPTURECOUNT, &preg->re_nsub); }
Dynamic _hx_regexp_new_options(String s, String opt) { hx::strbuf buf; const char *o = opt.utf8_str(&buf); int options = PCRE_UCP; while( *o ) { switch( *o++ ) { case 'i': options |= PCRE_CASELESS; break; case 's': options |= PCRE_DOTALL; break; case 'm': options |= PCRE_MULTILINE; break; case 'g': options |= PCRE_UNGREEDY; break; case 'u': break; default: hx::Throw( HX_CSTRING("Regexp unknown modifier : ") + String::fromCharCode(o[-1]) ); break; } } #ifdef HX_SMART_STRINGS if (s.isUTF16Encoded()) { const char *error = 0; int err_offset = 0; pcre16 *p = pcre16_compile((PCRE_SPTR16)s.raw_wptr(),options|PCRE_UTF16,&error,&err_offset,NULL); if( !p ) hx::Throw( HX_CSTRING("Regexp compilation error : ")+String(error)+HX_CSTRING(" in ")+s); pcredata *pdata = new pcredata; pdata->create16(p,s,options); return pdata; } else #endif { const char *error = 0; int err_offset = 0; pcre *p = pcre_compile(s.utf8_str(),options|PCRE_UTF8,&error,&err_offset,NULL); if( !p ) hx::Throw( HX_CSTRING("Regexp compilation error : ")+String(error)+HX_CSTRING(" in ")+s); pcredata *pdata = new pcredata; pdata->create8(p,s,options); return pdata; } }
static const unsigned char *tables(int mode) { /* The purpose of this function to allow valgrind for reporting invalid reads and writes. */ static unsigned char *tables_copy; const char *errorptr; int erroroffset; const unsigned char *default_tables; #ifdef SUPPORT_PCRE8 pcre *regex; char null_str[1] = { 0 }; #else pcre16 *regex; PCRE_UCHAR16 null_str[1] = { 0 }; #endif if (mode) { if (tables_copy) free(tables_copy); tables_copy = NULL; return NULL; } if (tables_copy) return tables_copy; default_tables = NULL; #ifdef SUPPORT_PCRE8 regex = pcre_compile(null_str, 0, &errorptr, &erroroffset, NULL); if (regex) { pcre_fullinfo(regex, NULL, PCRE_INFO_DEFAULT_TABLES, &default_tables); pcre_free(regex); } #else regex = pcre16_compile(null_str, 0, &errorptr, &erroroffset, NULL); if (regex) { pcre16_fullinfo(regex, NULL, PCRE_INFO_DEFAULT_TABLES, &default_tables); pcre16_free(regex); } #endif /* Shouldn't ever happen. */ if (!default_tables) return NULL; /* Unfortunately this value cannot get from pcre_fullinfo. Since this is a test program, this is acceptable at the moment. */ tables_copy = (unsigned char *)malloc(1088); if (!tables_copy) return NULL; memcpy(tables_copy, default_tables, 1088); return tables_copy; }
static ejsval _ejs_RegExp_impl (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { EJSRegExp *re; if (EJSVAL_IS_UNDEFINED(_this)) { // called as a function _this = _ejs_object_new(_ejs_RegExp_prototype, &_ejs_RegExp_specops); } re = (EJSRegExp*)EJSVAL_TO_OBJECT(_this); re->pattern = _ejs_undefined; re->flags = _ejs_undefined; if (argc > 0) re->pattern = args[0]; if (argc > 1) re->flags = args[1]; if (!EJSVAL_IS_STRING(re->pattern)) EJS_NOT_IMPLEMENTED(); EJSPrimString *flat_pattern = _ejs_string_flatten (re->pattern); jschar* chars = flat_pattern->data.flat; const unsigned char* pcre16_tables = pcre16_maketables(); const char *pcre_error; int pcre_erroffset; re->compiled_pattern = pcre16_compile(chars, PCRE_UTF16 | PCRE_NO_UTF16_CHECK, &pcre_error, &pcre_erroffset, pcre16_tables); _ejs_object_define_value_property (_this, _ejs_atom_source, re->pattern, EJS_PROP_NOT_ENUMERABLE | EJS_PROP_NOT_CONFIGURABLE | EJS_PROP_NOT_WRITABLE); if (EJSVAL_IS_STRING(re->flags)) { EJSPrimString *flat_flags = _ejs_string_flatten(re->flags); chars = flat_flags->data.flat; for (int i = 0; i < flat_flags->length; i ++) { if (chars[i] == 'g' && !re->global) { re->global = EJS_TRUE; continue; } else if (chars[i] == 'i' && !re->ignoreCase) { re->ignoreCase = EJS_TRUE; continue; } else if (chars[i] == 'm' && !re->multiline) { re->multiline = EJS_TRUE; continue; } else if (chars[i] == 'y' && !re->sticky) { re->sticky = EJS_TRUE; continue; } else if (chars[i] == 'u' && !re->unicode) { re->unicode = EJS_TRUE; continue; } _ejs_throw_nativeerror_utf8 (EJS_SYNTAX_ERROR, "Invalid flag supplied to RegExp constructor"); } } return _this; }
RegExp* RegExp::create(const U16String& pattern, unsigned int flags) { RegExp* re = new RegExp(pattern, flags); int error = 0; #ifdef LIBJ_USE_PCRE16 const char* errstr; int fs = (flags & IGNORE_CASE ? PCRE_CASELESS : 0) | (flags & MULTILINE ? PCRE_MULTILINE : 0); re->code_ = pcre16_compile(pattern.c_str(), fs, &errstr, &error, NULL); #else iv::core::Space space; int fs = (flags & IGNORE_CASE ? iv::aero::IGNORE_CASE : 0) | (flags & MULTILINE ? iv::aero::MULTILINE : 0); re->code_ = iv::aero::Compile(&space, pattern, fs, &error); #endif if (!error && re->code_) { return re; } else { delete re; return NULL; } }
/* ** Substitutes part of the text */ const WCHAR* Measure::CheckSubstitute(const WCHAR* buffer) { static std::wstring str; if (m_Substitute.empty()) { return buffer; } str = buffer; if (!m_RegExpSubstitute) { for (size_t i = 0, isize = m_Substitute.size(); i < isize; i += 2) { if (!m_Substitute[i].empty()) { MakePlainSubstitute(str, i); } else if (str.empty()) { // Empty result and empty substitute -> use second str = m_Substitute[i + 1]; } } } else { int ovector[300]; for (size_t i = 0, isize = m_Substitute.size(); i < isize; i += 2) { const char* error; int errorOffset; int offset = 0; pcre16* re = pcre16_compile( (PCRE_SPTR16)m_Substitute[i].c_str(), PCRE_UTF16, &error, &errorOffset, nullptr); // Use default character tables. if (!re) { MakePlainSubstitute(str, i); LogNoticeF(this, L"Substitute: %S", error); } else { do { const int options = str.empty() ? 0 : PCRE_NOTEMPTY; const int rc = pcre16_exec( re, nullptr, (PCRE_SPTR16)str.c_str(), (int)str.length(), offset, options, // Empty string is not a valid match ovector, (int)_countof(ovector)); if (rc <= 0) { break; } std::wstring result = m_Substitute[i + 1]; if (rc > 1) { for (int j = rc - 1 ; j >= 0 ; --j) { int newStart = ovector[2 * j]; size_t inLength = ovector[2 * j + 1] - ovector[2 * j]; if (newStart < 0) break; // Match was not found, so skip to the next item WCHAR tmpName[64]; size_t cutLength = _snwprintf_s(tmpName, _TRUNCATE, L"\\%i", j); size_t start = 0, pos; do { pos = result.find(tmpName, start, cutLength); if (pos != std::string::npos) { result.replace(pos, cutLength, str, (size_t)newStart, inLength); start = pos + inLength; } } while (pos != std::string::npos); } } const int start = ovector[0]; const int length = ovector[1] - ovector[0]; str.replace(start, length, result); offset = start + (int)result.length(); } while (true); pcre16_free(re); } } } return str.c_str(); }
TCString CompileRegexp(TCString Regexp, int bAddAsUsualSubstring, int ID) { TCString Result(_T("")); sPcreCompileData s = {0}; int NewID = PcreCompileData.AddElem(s); PcreCompileData[NewID].ID = ID; if (!bAddAsUsualSubstring) { const char *Err; int ErrOffs; int Flags = PCRE_CASELESS; if (Regexp[0] == '/') { TCString OrigRegexp = Regexp; Regexp = Regexp.Right(Regexp.GetLen() - 1); TCHAR *pRegexpEnd = (TCHAR*)Regexp + Regexp.GetLen(); TCHAR *p = _tcsrchr(Regexp.GetBuffer(), '/'); if (!p) { Regexp = OrigRegexp; } else { *p = 0; Flags = 0; while (++p < pRegexpEnd) { switch (*p) { case 'i': Flags |= PCRE_CASELESS; break; case 'm': Flags |= PCRE_MULTILINE; break; case 's': Flags |= PCRE_DOTALL; break; case 'x': Flags |= PCRE_EXTENDED; break; case 'A': Flags |= PCRE_ANCHORED; break; case 'f': Flags |= PCRE_FIRSTLINE; break; case 'D': Flags |= PCRE_DOLLAR_ENDONLY; break; case 'U': Flags |= PCRE_UNGREEDY; break; case 'X': Flags |= PCRE_EXTRA; break; default: // Result += LogMessage(Translate("Warning, unknown pattern modifier '%c':\n"), *p ); break; } } } Regexp.ReleaseBuffer(); } PcreCompileData[NewID].pPcre = pcre16_compile(Regexp, PCRE_UTF8 | PCRE_NO_UTF8_CHECK | Flags, &Err, &ErrOffs, NULL); if (PcreCompileData[NewID].pPcre) { PcreCompileData[NewID].pExtra = NULL; PcreCompileData[NewID].pExtra = pcre16_study(PcreCompileData[NewID].pPcre, 0, &Err); } else { // Result += LogMessage(TranslateT("Syntax error in regexp\n%s\nat offset %d: %s."), (TCHAR*)Regexp, ErrOffs, (TCHAR*)ANSI2TCHAR(Err)) + _T("\n\n"); PcreCompileData[NewID].Pattern = Regexp; } } else PcreCompileData[NewID].Pattern = Regexp; return Result; }
static int regression_tests(void) { struct regression_test_case *current = regression_test_cases; const char *error; const char *cpu_info; int i, err_offs; int is_successful, is_ascii_pattern, is_ascii_input; int total = 0; int successful = 0; int counter = 0; #ifdef SUPPORT_PCRE8 pcre *re8; pcre_extra *extra8; int ovector8_1[32]; int ovector8_2[32]; int return_value8_1, return_value8_2; int utf8 = 0, ucp8 = 0; int disabled_flags8 = 0; #endif #ifdef SUPPORT_PCRE16 pcre16 *re16; pcre16_extra *extra16; int ovector16_1[32]; int ovector16_2[32]; int return_value16_1, return_value16_2; int utf16 = 0, ucp16 = 0; int disabled_flags16 = 0; int length16; #endif /* This test compares the behaviour of interpreter and JIT. Although disabling utf or ucp may make tests fail, if the pcre_exec result is the SAME, it is still considered successful from pcre_jit_test point of view. */ #ifdef SUPPORT_PCRE8 pcre_config(PCRE_CONFIG_JITTARGET, &cpu_info); #else pcre16_config(PCRE_CONFIG_JITTARGET, &cpu_info); #endif printf("Running JIT regression tests\n"); printf(" target CPU of SLJIT compiler: %s\n", cpu_info); #ifdef SUPPORT_PCRE8 pcre_config(PCRE_CONFIG_UTF8, &utf8); pcre_config(PCRE_CONFIG_UNICODE_PROPERTIES, &ucp8); if (!utf8) disabled_flags8 |= PCRE_UTF8; if (!ucp8) disabled_flags8 |= PCRE_UCP; printf(" in 8 bit mode with utf8 %s and ucp %s:\n", utf8 ? "enabled" : "disabled", ucp8 ? "enabled" : "disabled"); #endif #ifdef SUPPORT_PCRE16 pcre16_config(PCRE_CONFIG_UTF16, &utf16); pcre16_config(PCRE_CONFIG_UNICODE_PROPERTIES, &ucp16); if (!utf16) disabled_flags16 |= PCRE_UTF8; if (!ucp16) disabled_flags16 |= PCRE_UCP; printf(" in 16 bit mode with utf16 %s and ucp %s:\n", utf16 ? "enabled" : "disabled", ucp16 ? "enabled" : "disabled"); #endif while (current->pattern) { /* printf("\nPattern: %s :\n", current->pattern); */ total++; if (current->start_offset & F_PROPERTY) { is_ascii_pattern = 0; is_ascii_input = 0; } else { is_ascii_pattern = check_ascii(current->pattern); is_ascii_input = check_ascii(current->input); } error = NULL; #ifdef SUPPORT_PCRE8 re8 = NULL; if (!(current->start_offset & F_NO8)) re8 = pcre_compile(current->pattern, current->flags & ~(PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART | disabled_flags8), &error, &err_offs, tables(0)); extra8 = NULL; if (re8) { error = NULL; extra8 = pcre_study(re8, PCRE_STUDY_JIT_COMPILE, &error); if (!extra8) { printf("\n8 bit: Cannot study pattern: %s\n", current->pattern); pcre_free(re8); re8 = NULL; } if (!(extra8->flags & PCRE_EXTRA_EXECUTABLE_JIT)) { printf("\n8 bit: JIT compiler does not support: %s\n", current->pattern); pcre_free_study(extra8); pcre_free(re8); re8 = NULL; } } else if (((utf8 && ucp8) || is_ascii_pattern) && !(current->start_offset & F_NO8)) printf("\n8 bit: Cannot compile pattern: %s\n", current->pattern); #endif #ifdef SUPPORT_PCRE16 if ((current->flags & PCRE_UTF8) || (current->start_offset & F_FORCECONV)) convert_utf8_to_utf16(current->pattern, regtest_buf, NULL, REGTEST_MAX_LENGTH); else copy_char8_to_char16(current->pattern, regtest_buf, REGTEST_MAX_LENGTH); re16 = NULL; if (!(current->start_offset & F_NO16)) re16 = pcre16_compile(regtest_buf, current->flags & ~(PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART | disabled_flags16), &error, &err_offs, tables(0)); extra16 = NULL; if (re16) { error = NULL; extra16 = pcre16_study(re16, PCRE_STUDY_JIT_COMPILE, &error); if (!extra16) { printf("\n16 bit: Cannot study pattern: %s\n", current->pattern); pcre16_free(re16); re16 = NULL; } if (!(extra16->flags & PCRE_EXTRA_EXECUTABLE_JIT)) { printf("\n16 bit: JIT compiler does not support: %s\n", current->pattern); pcre16_free_study(extra16); pcre16_free(re16); re16 = NULL; } } else if (((utf16 && ucp16) || is_ascii_pattern) && !(current->start_offset & F_NO16)) printf("\n16 bit: Cannot compile pattern: %s\n", current->pattern); #endif counter++; if ((counter & 0x3) != 0) { #ifdef SUPPORT_PCRE8 setstack8(NULL); #endif #ifdef SUPPORT_PCRE16 setstack16(NULL); #endif } #ifdef SUPPORT_PCRE8 return_value8_1 = -1000; return_value8_2 = -1000; for (i = 0; i < 32; ++i) ovector8_1[i] = -2; for (i = 0; i < 32; ++i) ovector8_2[i] = -2; if (re8) { setstack8(extra8); return_value8_1 = pcre_exec(re8, extra8, current->input, strlen(current->input), current->start_offset & OFFSET_MASK, current->flags & (PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART), ovector8_1, 32); return_value8_2 = pcre_exec(re8, NULL, current->input, strlen(current->input), current->start_offset & OFFSET_MASK, current->flags & (PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART), ovector8_2, 32); } #endif #ifdef SUPPORT_PCRE16 return_value16_1 = -1000; return_value16_2 = -1000; for (i = 0; i < 32; ++i) ovector16_1[i] = -2; for (i = 0; i < 32; ++i) ovector16_2[i] = -2; if (re16) { setstack16(extra16); if ((current->flags & PCRE_UTF8) || (current->start_offset & F_FORCECONV)) length16 = convert_utf8_to_utf16(current->input, regtest_buf, regtest_offsetmap, REGTEST_MAX_LENGTH); else length16 = copy_char8_to_char16(current->input, regtest_buf, REGTEST_MAX_LENGTH); return_value16_1 = pcre16_exec(re16, extra16, regtest_buf, length16, current->start_offset & OFFSET_MASK, current->flags & (PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART), ovector16_1, 32); return_value16_2 = pcre16_exec(re16, NULL, regtest_buf, length16, current->start_offset & OFFSET_MASK, current->flags & (PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART), ovector16_2, 32); } #endif /* If F_DIFF is set, just run the test, but do not compare the results. Segfaults can still be captured. */ is_successful = 1; if (!(current->start_offset & F_DIFF)) { #if defined SUPPORT_PCRE8 && defined SUPPORT_PCRE16 if (utf8 == utf16 && !(current->start_offset & F_FORCECONV)) { /* All results must be the same. */ if (return_value8_1 != return_value8_2 || return_value8_1 != return_value16_1 || return_value8_1 != return_value16_2) { printf("\n8 and 16 bit: Return value differs(%d:%d:%d:%d): [%d] '%s' @ '%s'\n", return_value8_1, return_value8_2, return_value16_1, return_value16_2, total, current->pattern, current->input); is_successful = 0; } else if (return_value8_1 >= 0) { return_value8_1 *= 2; /* Transform back the results. */ if (current->flags & PCRE_UTF8) { for (i = 0; i < return_value8_1; ++i) { if (ovector16_1[i] >= 0) ovector16_1[i] = regtest_offsetmap[ovector16_1[i]]; if (ovector16_2[i] >= 0) ovector16_2[i] = regtest_offsetmap[ovector16_2[i]]; } } for (i = 0; i < return_value8_1; ++i) if (ovector8_1[i] != ovector8_2[i] || ovector8_1[i] != ovector16_1[i] || ovector8_1[i] != ovector16_2[i]) { printf("\n8 and 16 bit: Ovector[%d] value differs(%d:%d:%d:%d): [%d] '%s' @ '%s' \n", i, ovector8_1[i], ovector8_2[i], ovector16_1[i], ovector16_2[i], total, current->pattern, current->input); is_successful = 0; } } } else { #endif /* SUPPORT_PCRE8 && SUPPORT_PCRE16 */ /* Only the 8 bit and 16 bit results must be equal. */ #ifdef SUPPORT_PCRE8 if (return_value8_1 != return_value8_2) { printf("\n8 bit: Return value differs(%d:%d): [%d] '%s' @ '%s'\n", return_value8_1, return_value8_2, total, current->pattern, current->input); is_successful = 0; } else if (return_value8_1 >= 0) { return_value8_1 *= 2; for (i = 0; i < return_value8_1; ++i) if (ovector8_1[i] != ovector8_2[i]) { printf("\n8 bit: Ovector[%d] value differs(%d:%d): [%d] '%s' @ '%s'\n", i, ovector8_1[i], ovector8_2[i], total, current->pattern, current->input); is_successful = 0; } } #endif #ifdef SUPPORT_PCRE16 if (return_value16_1 != return_value16_2) { printf("\n16 bit: Return value differs(%d:%d): [%d] '%s' @ '%s'\n", return_value16_1, return_value16_2, total, current->pattern, current->input); is_successful = 0; } else if (return_value16_1 >= 0) { return_value16_1 *= 2; for (i = 0; i < return_value16_1; ++i) if (ovector16_1[i] != ovector16_2[i]) { printf("\n16 bit: Ovector[%d] value differs(%d:%d): [%d] '%s' @ '%s'\n", i, ovector16_1[i], ovector16_2[i], total, current->pattern, current->input); is_successful = 0; } } #endif #if defined SUPPORT_PCRE8 && defined SUPPORT_PCRE16 } #endif /* SUPPORT_PCRE8 && SUPPORT_PCRE16 */ } if (is_successful) { #ifdef SUPPORT_PCRE8 if (!(current->start_offset & F_NO8) && ((utf8 && ucp8) || is_ascii_input)) { if (return_value8_1 < 0 && !(current->start_offset & F_NOMATCH)) { printf("8 bit: Test should match: [%d] '%s' @ '%s'\n", total, current->pattern, current->input); is_successful = 0; } if (return_value8_1 >= 0 && (current->start_offset & F_NOMATCH)) { printf("8 bit: Test should not match: [%d] '%s' @ '%s'\n", total, current->pattern, current->input); is_successful = 0; } } #endif #ifdef SUPPORT_PCRE16 if (!(current->start_offset & F_NO16) && ((utf16 && ucp16) || is_ascii_input)) { if (return_value16_1 < 0 && !(current->start_offset & F_NOMATCH)) { printf("16 bit: Test should match: [%d] '%s' @ '%s'\n", total, current->pattern, current->input); is_successful = 0; } if (return_value16_1 >= 0 && (current->start_offset & F_NOMATCH)) { printf("16 bit: Test should not match: [%d] '%s' @ '%s'\n", total, current->pattern, current->input); is_successful = 0; } } #endif } if (is_successful) successful++; #ifdef SUPPORT_PCRE8 if (re8) { pcre_free_study(extra8); pcre_free(re8); } #endif #ifdef SUPPORT_PCRE16 if (re16) { pcre16_free_study(extra16); pcre16_free(re16); } #endif /* printf("[%d-%d|%d-%d]%s", ovector8_1[0], ovector8_1[1], ovector16_1[0], ovector16_1[1], (current->flags & PCRE_CASELESS) ? "C" : ""); */ printf("."); fflush(stdout); current++; } tables(1); #ifdef SUPPORT_PCRE8 setstack8(NULL); #endif #ifdef SUPPORT_PCRE16 setstack16(NULL); #endif if (total == successful) { printf("\nAll JIT regression tests are successfully passed.\n"); return 0; } else { printf("\nSuccessful test ratio: %d%% (%d failed)\n", successful * 100 / total, total - successful); return 1; } }
void IfActions::DoIfActions(Measure& measure, double value) { // IfEqual if (!m_EqualAction.empty()) { if ((int64_t)value == m_EqualValue) { if (!m_EqualCommitted) { m_EqualCommitted = true; // To avoid infinite loop from !Update GetRainmeter().ExecuteCommand(m_EqualAction.c_str(), measure.GetSkin()); } } else { m_EqualCommitted = false; } } // IfAbove if (!m_AboveAction.empty()) { if (value > m_AboveValue) { if (!m_AboveCommitted) { m_AboveCommitted = true; // To avoid infinite loop from !Update GetRainmeter().ExecuteCommand(m_AboveAction.c_str(), measure.GetSkin()); } } else { m_AboveCommitted = false; } } // IfBelow if (!m_BelowAction.empty()) { if (value < m_BelowValue) { if (!m_BelowCommitted) { m_BelowCommitted = true; // To avoid infinite loop from !Update GetRainmeter().ExecuteCommand(m_BelowAction.c_str(), measure.GetSkin()); } } else { m_BelowCommitted = false; } } // IfCondition int i = 0; for (auto& item : m_Conditions) { ++i; if (!item.value.empty() && (!item.tAction.empty() || !item.fAction.empty())) { double result = 0.0; const WCHAR* errMsg = MathParser::Parse( item.value.c_str(), &result, measure.GetCurrentMeasureValue, &measure); if (errMsg != nullptr) { if (!item.parseError) { if (i == 1) { LogErrorF(&measure, L"%s: IfCondition=%s", errMsg, item.value.c_str()); } else { LogErrorF(&measure, L"%s: IfCondition%i=%s", errMsg, i, item.value.c_str()); } item.parseError = true; } } else { item.parseError = false; if (result == 1.0) // "True" { item.fCommitted = false; if (m_ConditionMode || !item.tCommitted) { item.tCommitted = true; GetRainmeter().ExecuteCommand(item.tAction.c_str(), measure.GetSkin()); } } else if (result == 0.0) // "False" { item.tCommitted = false; if (m_ConditionMode || !item.fCommitted) { item.fCommitted = true; GetRainmeter().ExecuteCommand(item.fAction.c_str(), measure.GetSkin()); } } } } } // IfMatch i = 0; for (auto& item : m_Matches) { ++i; if (!item.value.empty() && (!item.tAction.empty() || !item.fAction.empty())) { const char* error; int errorOffset; pcre16* re = pcre16_compile( (PCRE_SPTR16)item.value.c_str(), PCRE_UTF16, &error, &errorOffset, nullptr); if (!re) { if (!item.parseError) { if (i == 1) { LogErrorF(&measure, L"Error: \"%S\" in IfMatch=%s", error, item.value.c_str()); } else { LogErrorF(&measure, L"Error: \"%S\" in IfMatch%i=%s", error, i, item.value.c_str()); } item.parseError = true; } } else { item.parseError = false; const WCHAR* str = measure.GetStringValue(); int strLen = str ? (int)wcslen(str) : 0; int ovector[300]; int rc = pcre16_exec( re, nullptr, (PCRE_SPTR16)str, (int)strLen, 0, 0, ovector, (int)_countof(ovector)); if (rc > 0) // Match { item.fCommitted = false; if (m_MatchMode || !item.tCommitted) { item.tCommitted = true; GetRainmeter().ExecuteCommand(item.tAction.c_str(), measure.GetSkin()); } } else // Not Match { item.tCommitted = false; if (m_MatchMode || !item.fCommitted) { item.fCommitted = true; GetRainmeter().ExecuteCommand(item.fAction.c_str(), measure.GetSkin()); } } } // Release memory used for the compiled pattern pcre16_free(re); } } }
void ParseData(MeasureData* measure, const BYTE* rawData, DWORD rawSize, bool utf16Data) { const int UTF16_CODEPAGE = 1200; if (measure->codepage == UTF16_CODEPAGE) { utf16Data = true; } const char* error; int erroffset; int ovector[OVECCOUNT]; int rc; bool doErrorAction = false; // Compile the regular expression in the first argument pcre16* re = pcre16_compile( (PCRE_SPTR16)measure->regExp.c_str(), PCRE_UTF16, &error, &erroffset, nullptr); if (re != nullptr) { // Compilation succeeded: match the subject in the second argument std::wstring buffer; auto data = (const WCHAR*)rawData; DWORD dataLength = rawSize / 2; if (!utf16Data) { buffer = StringUtil::Widen((LPCSTR)rawData, rawSize, measure->codepage); data = buffer.c_str(); dataLength = (DWORD)buffer.length(); } rc = pcre16_exec(re, nullptr, (PCRE_SPTR16)data, dataLength, 0, 0, ovector, OVECCOUNT); if (rc >= 0) { if (rc == 0) { // The output vector wasn't big enough RmLog(measure->rm, LOG_ERROR, L"WebParser: Too many substrings"); } else { if (measure->stringIndex < rc) { if (measure->debug != 0) { for (int i = 0; i < rc; ++i) { const WCHAR* match = data + ovector[2 * i]; const int matchLen = min(ovector[2 * i + 1] - ovector[2 * i], 256); RmLogF(measure->rm, LOG_DEBUG, L"WebParser: Index %2d: %.*s", i, matchLen, match); } } const WCHAR* match = data + ovector[2 * measure->stringIndex]; int matchLen = ovector[2 * measure->stringIndex + 1] - ovector[2 * measure->stringIndex]; EnterCriticalSection(&g_CriticalSection); measure->resultString.assign(match, matchLen); DecodeReferences(measure->resultString, measure->decodeCharacterReference); LeaveCriticalSection(&g_CriticalSection); } else { RmLog(measure->rm, LOG_WARNING, L"WebParser: Not enough substrings"); // Clear the old result EnterCriticalSection(&g_CriticalSection); measure->resultString.clear(); if (measure->download) { if (measure->downloadFile.empty()) // cache mode { if (!measure->downloadedFile.empty()) { // Delete old downloaded file DeleteFile(measure->downloadedFile.c_str()); } } measure->downloadedFile.clear(); } LeaveCriticalSection(&g_CriticalSection); } // Update the references std::vector<MeasureData*>::iterator i = g_Measures.begin(); std::wstring compareStr = L"["; compareStr += RmGetMeasureName(measure->rm); compareStr += L']'; for ( ; i != g_Measures.end(); ++i) { if (measure->skin == (*i)->skin && StringUtil::CaseInsensitiveFind((*i)->url, compareStr) != std::wstring::npos) { if ((*i)->stringIndex < rc) { const WCHAR* match = data + ovector[2 * (*i)->stringIndex]; int matchLen = ovector[2 * (*i)->stringIndex + 1] - ovector[2 * (*i)->stringIndex]; if (!(*i)->regExp.empty()) { // Change the index and parse the substring int index = (*i)->stringIndex; (*i)->stringIndex = (*i)->stringIndex2; ParseData((*i), (BYTE*)match, matchLen * 2, true); (*i)->stringIndex = index; } else { // Set the result EnterCriticalSection(&g_CriticalSection); // Substitude the [measure] with result (*i)->resultString = (*i)->url; (*i)->resultString.replace( StringUtil::CaseInsensitiveFind((*i)->resultString, compareStr), compareStr.size(), match, matchLen); DecodeReferences((*i)->resultString, (*i)->decodeCharacterReference); // Start download threads for the references if ((*i)->download) { // Start the download thread unsigned int id; HANDLE threadHandle = (HANDLE)_beginthreadex(nullptr, 0, NetworkDownloadThreadProc, (*i), 0, &id); if (threadHandle) { (*i)->dlThreadHandle = threadHandle; } } LeaveCriticalSection(&g_CriticalSection); } } else { RmLog((*i)->rm, LOG_WARNING, L"WebParser: Not enough substrings"); // Clear the old result EnterCriticalSection(&g_CriticalSection); (*i)->resultString.clear(); if ((*i)->download) { if ((*i)->downloadFile.empty()) // cache mode { if (!(*i)->downloadedFile.empty()) { // Delete old downloaded file DeleteFile((*i)->downloadedFile.c_str()); } } (*i)->downloadedFile.clear(); } LeaveCriticalSection(&g_CriticalSection); } } } } } else { // Matching failed: handle error cases RmLogF(measure->rm, LOG_ERROR, L"WebParser: RegExp matching error (%d)", rc); doErrorAction = true; EnterCriticalSection(&g_CriticalSection); measure->resultString = measure->errorString; // Update the references std::vector<MeasureData*>::iterator i = g_Measures.begin(); std::wstring compareStr = L"["; compareStr += RmGetMeasureName(measure->rm); compareStr += L']'; for ( ; i != g_Measures.end(); ++i) { if ((StringUtil::CaseInsensitiveFind((*i)->url, compareStr) != std::wstring::npos) && (measure->skin == (*i)->skin)) { (*i)->resultString = (*i)->errorString; } } LeaveCriticalSection(&g_CriticalSection); } // Release memory used for the compiled pattern pcre16_free(re); } else { // Compilation failed. RmLogF(measure->rm, LOG_ERROR, L"WebParser: RegExp error at offset %d: %S", erroffset, error); doErrorAction = true; } if (measure->download) { // Start the download thread unsigned int id; HANDLE threadHandle = (HANDLE)_beginthreadex(nullptr, 0, NetworkDownloadThreadProc, measure, 0, &id); if (threadHandle) { measure->dlThreadHandle = threadHandle; } } if (doErrorAction && !measure->onRegExpErrAction.empty()) { RmExecute(measure->skin, measure->onRegExpErrAction.c_str()); } else if (!measure->download && !measure->finishAction.empty()) { RmExecute(measure->skin, measure->finishAction.c_str()); } }