#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "pcre2_internal.h"
#define TYPE_OPTIONS (PCRE2_CONVERT_GLOB| \
PCRE2_CONVERT_POSIX_BASIC|PCRE2_CONVERT_POSIX_EXTENDED)
#define ALL_OPTIONS (PCRE2_CONVERT_UTF|PCRE2_CONVERT_NO_UTF_CHECK| \
PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR| \
PCRE2_CONVERT_GLOB_NO_STARSTAR| \
TYPE_OPTIONS)
#define DUMMY_BUFFER_SIZE 100
#define STR_BACKSLASH_A STR_BACKSLASH STR_A
#define STR_BACKSLASH_z STR_BACKSLASH STR_z
#define STR_COLON_RIGHT_SQUARE_BRACKET STR_COLON STR_RIGHT_SQUARE_BRACKET
#define STR_DOT_STAR_LOOKBEHIND STR_DOT STR_ASTERISK STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_LESS_THAN_SIGN STR_EQUALS_SIGN
#define STR_LOOKAHEAD_NOT_DOT STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_EXCLAMATION_MARK STR_BACKSLASH STR_DOT STR_RIGHT_PARENTHESIS
#define STR_QUERY_s STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_s STR_RIGHT_PARENTHESIS
#define STR_STAR_NUL STR_LEFT_PARENTHESIS STR_ASTERISK STR_N STR_U STR_L STR_RIGHT_PARENTHESIS
enum { POSIX_START_REGEX, POSIX_ANCHORED, POSIX_NOT_BRACKET,
POSIX_CLASS_NOT_STARTED, POSIX_CLASS_STARTING, POSIX_CLASS_STARTED };
#define PUTCHARS(string) \
{ \
for (const char *s = string; *s != 0; s++) \
{ \
if (p >= endp) return PCRE2_ERROR_NOMEMORY; \
*p++ = *s; \
} \
}
static const char *pcre2_escaped_literals =
STR_BACKSLASH STR_QUESTION_MARK STR_ASTERISK STR_PLUS
STR_VERTICAL_LINE STR_DOT STR_CIRCUMFLEX_ACCENT STR_DOLLAR_SIGN
STR_LEFT_CURLY_BRACKET STR_RIGHT_CURLY_BRACKET
STR_LEFT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET
STR_LEFT_PARENTHESIS STR_RIGHT_PARENTHESIS;
static const char *posix_meta_escapes =
STR_LEFT_PARENTHESIS STR_RIGHT_PARENTHESIS
STR_LEFT_CURLY_BRACKET STR_RIGHT_CURLY_BRACKET
STR_1 STR_2 STR_3 STR_4 STR_5 STR_6 STR_7 STR_8 STR_9;
static int
convert_posix(uint32_t pattype, PCRE2_SPTR pattern, PCRE2_SIZE plength,
BOOL utf, PCRE2_UCHAR *use_buffer, PCRE2_SIZE use_length,
PCRE2_SIZE *bufflenptr, BOOL dummyrun, pcre2_convert_context *ccontext)
{
PCRE2_SPTR posix = pattern;
PCRE2_UCHAR *p = use_buffer;
PCRE2_UCHAR *pp = p;
PCRE2_UCHAR *endp = p + use_length - 1;
PCRE2_SIZE convlength = 0;
uint32_t bracount = 0;
uint32_t posix_state = POSIX_START_REGEX;
uint32_t lastspecial = 0;
BOOL extended = (pattype & PCRE2_CONVERT_POSIX_EXTENDED) != 0;
BOOL nextisliteral = FALSE;
(void)utf;
(void)ccontext;
*bufflenptr = plength;
PUTCHARS(STR_STAR_NUL);
while (plength > 0)
{
uint32_t c, sc;
int clength = 1;
convlength += p - pp;
if (dummyrun) p = use_buffer;
pp = p;
#ifndef SUPPORT_UNICODE
c = *posix;
#else
GETCHARLENTEST(c, posix, clength);
#endif
posix += clength;
plength -= clength;
sc = nextisliteral? 0 : c;
nextisliteral = FALSE;
if (posix_state >= POSIX_CLASS_NOT_STARTED)
{
if (c == CHAR_RIGHT_SQUARE_BRACKET)
{
PUTCHARS(STR_RIGHT_SQUARE_BRACKET);
posix_state = POSIX_NOT_BRACKET;
}
else
{
switch (posix_state)
{
case POSIX_CLASS_STARTED:
if (c <= 127 && islower(c)) break;
posix_state = POSIX_CLASS_NOT_STARTED;
if (c == CHAR_COLON && plength > 0 &&
*posix == CHAR_RIGHT_SQUARE_BRACKET)
{
PUTCHARS(STR_COLON_RIGHT_SQUARE_BRACKET);
plength--;
posix++;
continue;
}
case POSIX_CLASS_NOT_STARTED:
if (c == CHAR_LEFT_SQUARE_BRACKET)
posix_state = POSIX_CLASS_STARTING;
break;
case POSIX_CLASS_STARTING:
if (c == CHAR_COLON) posix_state = POSIX_CLASS_STARTED;
break;
}
if (c == CHAR_BACKSLASH) PUTCHARS(STR_BACKSLASH);
if (p + clength > endp) return PCRE2_ERROR_NOMEMORY;
memcpy(p, posix - clength, CU2BYTES(clength));
p += clength;
}
}
else switch(sc)
{
case CHAR_LEFT_SQUARE_BRACKET:
PUTCHARS(STR_LEFT_SQUARE_BRACKET);
#ifdef NEVER
if (plength >= 6)
{
if (posix[0] == CHAR_LEFT_SQUARE_BRACKET &&
posix[1] == CHAR_COLON &&
(posix[2] == CHAR_LESS_THAN_SIGN ||
posix[2] == CHAR_GREATER_THAN_SIGN) &&
posix[3] == CHAR_COLON &&
posix[4] == CHAR_RIGHT_SQUARE_BRACKET &&
posix[5] == CHAR_RIGHT_SQUARE_BRACKET)
{
if (p + 6 > endp) return PCRE2_ERROR_NOMEMORY;
memcpy(p, posix, CU2BYTES(6));
p += 6;
posix += 6;
plength -= 6;
continue;
}
}
#endif
posix_state = POSIX_CLASS_NOT_STARTED;
if (plength > 0)
{
if (*posix == CHAR_CIRCUMFLEX_ACCENT)
{
posix++;
plength--;
PUTCHARS(STR_CIRCUMFLEX_ACCENT);
}
if (plength > 0 && *posix == CHAR_RIGHT_SQUARE_BRACKET)
{
posix++;
plength--;
PUTCHARS(STR_RIGHT_SQUARE_BRACKET);
}
}
break;
case CHAR_BACKSLASH:
if (plength == 0) return PCRE2_ERROR_END_BACKSLASH;
if (extended) nextisliteral = TRUE; else
{
if (*posix < 127 && strchr(posix_meta_escapes, *posix) != NULL)
{
if (isdigit(*posix)) PUTCHARS(STR_BACKSLASH);
if (p + 1 > endp) return PCRE2_ERROR_NOMEMORY;
lastspecial = *p++ = *posix++;
plength--;
}
else nextisliteral = TRUE;
}
break;
case CHAR_RIGHT_PARENTHESIS:
if (!extended || bracount == 0) goto ESCAPE_LITERAL;
bracount--;
goto COPY_SPECIAL;
case CHAR_LEFT_PARENTHESIS:
bracount++;
case CHAR_QUESTION_MARK:
case CHAR_PLUS:
case CHAR_LEFT_CURLY_BRACKET:
case CHAR_RIGHT_CURLY_BRACKET:
case CHAR_VERTICAL_LINE:
if (!extended) goto ESCAPE_LITERAL;
case CHAR_DOT:
case CHAR_DOLLAR_SIGN:
posix_state = POSIX_NOT_BRACKET;
COPY_SPECIAL:
lastspecial = c;
if (p + 1 > endp) return PCRE2_ERROR_NOMEMORY;
*p++ = c;
break;
case CHAR_ASTERISK:
if (lastspecial != CHAR_ASTERISK)
{
if (!extended && (posix_state < POSIX_NOT_BRACKET ||
lastspecial == CHAR_LEFT_PARENTHESIS))
goto ESCAPE_LITERAL;
goto COPY_SPECIAL;
}
break;
case CHAR_CIRCUMFLEX_ACCENT:
if (extended) goto COPY_SPECIAL;
if (posix_state == POSIX_START_REGEX ||
lastspecial == CHAR_LEFT_PARENTHESIS)
{
posix_state = POSIX_ANCHORED;
goto COPY_SPECIAL;
}
default:
if (c < 128 && strchr(pcre2_escaped_literals, c) != NULL)
{
ESCAPE_LITERAL:
PUTCHARS(STR_BACKSLASH);
}
lastspecial = 0xff;
if (p + clength > endp) return PCRE2_ERROR_NOMEMORY;
memcpy(p, posix - clength, CU2BYTES(clength));
p += clength;
posix_state = POSIX_NOT_BRACKET;
break;
}
}
if (posix_state >= POSIX_CLASS_NOT_STARTED)
return PCRE2_ERROR_MISSING_SQUARE_BRACKET;
convlength += p - pp;
*bufflenptr = convlength;
*p++ = 0;
return 0;
}
typedef struct pcre2_output_context {
PCRE2_UCHAR *output;
PCRE2_SPTR output_end;
PCRE2_SIZE output_size;
uint8_t out_str[8];
} pcre2_output_context;
static void
convert_glob_write(pcre2_output_context *out, PCRE2_UCHAR chr)
{
out->output_size++;
if (out->output < out->output_end)
*out->output++ = chr;
}
static void
convert_glob_write_str(pcre2_output_context *out, PCRE2_SIZE length)
{
uint8_t *out_str = out->out_str;
PCRE2_UCHAR *output = out->output;
PCRE2_SPTR output_end = out->output_end;
PCRE2_SIZE output_size = out->output_size;
do
{
output_size++;
if (output < output_end)
*output++ = *out_str++;
}
while (--length != 0);
out->output = output;
out->output_size = output_size;
}
static void
convert_glob_print_separator(pcre2_output_context *out,
PCRE2_UCHAR separator, BOOL with_escape)
{
if (with_escape)
convert_glob_write(out, CHAR_BACKSLASH);
convert_glob_write(out, separator);
}
static void
convert_glob_print_wildcard(pcre2_output_context *out,
PCRE2_UCHAR separator, BOOL with_escape)
{
out->out_str[0] = CHAR_LEFT_SQUARE_BRACKET;
out->out_str[1] = CHAR_CIRCUMFLEX_ACCENT;
convert_glob_write_str(out, 2);
convert_glob_print_separator(out, separator, with_escape);
convert_glob_write(out, CHAR_RIGHT_SQUARE_BRACKET);
}
static int
convert_glob_parse_class(PCRE2_SPTR *from, PCRE2_SPTR pattern_end,
pcre2_output_context *out)
{
static const char *posix_classes = "alnum:alpha:ascii:blank:cntrl:digit:"
"graph:lower:print:punct:space:upper:word:xdigit:";
PCRE2_SPTR start = *from + 1;
PCRE2_SPTR pattern = start;
const char *class_ptr;
PCRE2_UCHAR c;
int class_index;
while (TRUE)
{
if (pattern >= pattern_end) return 0;
c = *pattern++;
if (c < CHAR_a || c > CHAR_z) break;
}
if (c != CHAR_COLON || pattern >= pattern_end ||
*pattern != CHAR_RIGHT_SQUARE_BRACKET)
return 0;
class_ptr = posix_classes;
class_index = 1;
while (TRUE)
{
if (*class_ptr == CHAR_NUL) return 0;
pattern = start;
while (*pattern == (PCRE2_UCHAR) *class_ptr)
{
if (*pattern == CHAR_COLON)
{
pattern += 2;
start -= 2;
do convert_glob_write(out, *start++); while (start < pattern);
*from = pattern;
return class_index;
}
pattern++;
class_ptr++;
}
while (*class_ptr != CHAR_COLON) class_ptr++;
class_ptr++;
class_index++;
}
}
static BOOL
convert_glob_char_in_class(int class_index, PCRE2_UCHAR c)
{
#if PCRE2_CODE_UNIT_WIDTH != 8
if (c > 0xff)
{
return 0;
}
#endif
switch (class_index)
{
case 1: return isalnum(c);
case 2: return isalpha(c);
case 3: return 1;
case 4: return c == CHAR_HT || c == CHAR_SPACE;
case 5: return iscntrl(c);
case 6: return isdigit(c);
case 7: return isgraph(c);
case 8: return islower(c);
case 9: return isprint(c);
case 10: return ispunct(c);
case 11: return isspace(c);
case 12: return isupper(c);
case 13: return isalnum(c) || c == CHAR_UNDERSCORE;
default: return isxdigit(c);
}
}
static int
convert_glob_parse_range(PCRE2_SPTR *from, PCRE2_SPTR pattern_end,
pcre2_output_context *out, BOOL utf, PCRE2_UCHAR separator,
BOOL with_escape, PCRE2_UCHAR escape, BOOL no_wildsep)
{
BOOL is_negative = FALSE;
BOOL separator_seen = FALSE;
BOOL has_prev_c;
PCRE2_SPTR pattern = *from;
PCRE2_SPTR char_start = NULL;
uint32_t c, prev_c;
int len, class_index;
(void)utf;
if (pattern >= pattern_end)
{
*from = pattern;
return PCRE2_ERROR_MISSING_SQUARE_BRACKET;
}
if (*pattern == CHAR_EXCLAMATION_MARK
|| *pattern == CHAR_CIRCUMFLEX_ACCENT)
{
pattern++;
if (pattern >= pattern_end)
{
*from = pattern;
return PCRE2_ERROR_MISSING_SQUARE_BRACKET;
}
is_negative = TRUE;
out->out_str[0] = CHAR_LEFT_SQUARE_BRACKET;
out->out_str[1] = CHAR_CIRCUMFLEX_ACCENT;
len = 2;
if (!no_wildsep)
{
if (with_escape)
{
out->out_str[len] = CHAR_BACKSLASH;
len++;
}
out->out_str[len] = (uint8_t) separator;
}
convert_glob_write_str(out, len + 1);
}
else
convert_glob_write(out, CHAR_LEFT_SQUARE_BRACKET);
has_prev_c = FALSE;
prev_c = 0;
if (*pattern == CHAR_RIGHT_SQUARE_BRACKET)
{
out->out_str[0] = CHAR_BACKSLASH;
out->out_str[1] = CHAR_RIGHT_SQUARE_BRACKET;
convert_glob_write_str(out, 2);
has_prev_c = TRUE;
prev_c = CHAR_RIGHT_SQUARE_BRACKET;
pattern++;
}
while (pattern < pattern_end)
{
char_start = pattern;
GETCHARINCTEST(c, pattern);
if (c == CHAR_RIGHT_SQUARE_BRACKET)
{
convert_glob_write(out, c);
if (!is_negative && !no_wildsep && separator_seen)
{
out->out_str[0] = CHAR_LEFT_PARENTHESIS;
out->out_str[1] = CHAR_QUESTION_MARK;
out->out_str[2] = CHAR_LESS_THAN_SIGN;
out->out_str[3] = CHAR_EXCLAMATION_MARK;
convert_glob_write_str(out, 4);
convert_glob_print_separator(out, separator, with_escape);
convert_glob_write(out, CHAR_RIGHT_PARENTHESIS);
}
*from = pattern;
return 0;
}
if (pattern >= pattern_end) break;
if (c == CHAR_LEFT_SQUARE_BRACKET && *pattern == CHAR_COLON)
{
*from = pattern;
class_index = convert_glob_parse_class(from, pattern_end, out);
if (class_index != 0)
{
pattern = *from;
has_prev_c = FALSE;
prev_c = 0;
if (!is_negative &&
convert_glob_char_in_class (class_index, separator))
separator_seen = TRUE;
continue;
}
}
else if (c == CHAR_MINUS && has_prev_c &&
*pattern != CHAR_RIGHT_SQUARE_BRACKET)
{
convert_glob_write(out, CHAR_MINUS);
char_start = pattern;
GETCHARINCTEST(c, pattern);
if (pattern >= pattern_end) break;
if (escape != 0 && c == escape)
{
char_start = pattern;
GETCHARINCTEST(c, pattern);
}
else if (c == CHAR_LEFT_SQUARE_BRACKET && *pattern == CHAR_COLON)
{
*from = pattern;
return PCRE2_ERROR_CONVERT_SYNTAX;
}
if (prev_c > c)
{
*from = pattern;
return PCRE2_ERROR_CONVERT_SYNTAX;
}
if (prev_c < separator && separator < c) separator_seen = TRUE;
has_prev_c = FALSE;
prev_c = 0;
}
else
{
if (escape != 0 && c == escape)
{
char_start = pattern;
GETCHARINCTEST(c, pattern);
if (pattern >= pattern_end) break;
}
has_prev_c = TRUE;
prev_c = c;
}
if (c == CHAR_LEFT_SQUARE_BRACKET || c == CHAR_RIGHT_SQUARE_BRACKET ||
c == CHAR_BACKSLASH || c == CHAR_MINUS)
convert_glob_write(out, CHAR_BACKSLASH);
if (c == separator) separator_seen = TRUE;
do convert_glob_write(out, *char_start++); while (char_start < pattern);
}
*from = pattern;
return PCRE2_ERROR_MISSING_SQUARE_BRACKET;
}
static void
convert_glob_print_commit(pcre2_output_context *out)
{
out->out_str[0] = CHAR_LEFT_PARENTHESIS;
out->out_str[1] = CHAR_ASTERISK;
out->out_str[2] = CHAR_C;
out->out_str[3] = CHAR_O;
out->out_str[4] = CHAR_M;
out->out_str[5] = CHAR_M;
out->out_str[6] = CHAR_I;
out->out_str[7] = CHAR_T;
convert_glob_write_str(out, 8);
convert_glob_write(out, CHAR_RIGHT_PARENTHESIS);
}
static int
convert_glob(uint32_t options, PCRE2_SPTR pattern, PCRE2_SIZE plength,
BOOL utf, PCRE2_UCHAR *use_buffer, PCRE2_SIZE use_length,
PCRE2_SIZE *bufflenptr, BOOL dummyrun, pcre2_convert_context *ccontext)
{
pcre2_output_context out;
PCRE2_SPTR pattern_start = pattern;
PCRE2_SPTR pattern_end = pattern + plength;
PCRE2_UCHAR separator = ccontext->glob_separator;
PCRE2_UCHAR escape = ccontext->glob_escape;
PCRE2_UCHAR c;
BOOL no_wildsep = (options & PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR) != 0;
BOOL no_starstar = (options & PCRE2_CONVERT_GLOB_NO_STARSTAR) != 0;
BOOL in_atomic = FALSE;
BOOL after_starstar = FALSE;
BOOL no_slash_z = FALSE;
BOOL with_escape, is_start, after_separator;
int result = 0;
(void)utf;
#ifdef SUPPORT_UNICODE
if (utf && (separator >= 128 || escape >= 128))
{
*bufflenptr = 0;
return PCRE2_ERROR_CONVERT_SYNTAX;
}
#endif
with_escape = strchr(pcre2_escaped_literals, separator) != NULL;
out.output = use_buffer;
out.output_end = use_buffer + use_length;
out.output_size = 0;
out.out_str[0] = CHAR_LEFT_PARENTHESIS;
out.out_str[1] = CHAR_QUESTION_MARK;
out.out_str[2] = CHAR_s;
out.out_str[3] = CHAR_RIGHT_PARENTHESIS;
convert_glob_write_str(&out, 4);
is_start = TRUE;
if (pattern < pattern_end && pattern[0] == CHAR_ASTERISK)
{
if (no_wildsep)
is_start = FALSE;
else if (!no_starstar && pattern + 1 < pattern_end &&
pattern[1] == CHAR_ASTERISK)
is_start = FALSE;
}
if (is_start)
{
out.out_str[0] = CHAR_BACKSLASH;
out.out_str[1] = CHAR_A;
convert_glob_write_str(&out, 2);
}
while (pattern < pattern_end)
{
c = *pattern++;
if (c == CHAR_ASTERISK)
{
is_start = pattern == pattern_start + 1;
if (in_atomic)
{
convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS);
in_atomic = FALSE;
}
if (!no_starstar && pattern < pattern_end && *pattern == CHAR_ASTERISK)
{
after_separator = is_start || (pattern[-2] == separator);
do pattern++; while (pattern < pattern_end &&
*pattern == CHAR_ASTERISK);
if (pattern >= pattern_end)
{
no_slash_z = TRUE;
break;
}
after_starstar = TRUE;
if (after_separator && escape != 0 && *pattern == escape &&
pattern + 1 < pattern_end && pattern[1] == separator)
pattern++;
if (is_start)
{
if (*pattern != separator) continue;
out.out_str[0] = CHAR_LEFT_PARENTHESIS;
out.out_str[1] = CHAR_QUESTION_MARK;
out.out_str[2] = CHAR_COLON;
out.out_str[3] = CHAR_BACKSLASH;
out.out_str[4] = CHAR_A;
out.out_str[5] = CHAR_VERTICAL_LINE;
convert_glob_write_str(&out, 6);
convert_glob_print_separator(&out, separator, with_escape);
convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS);
pattern++;
continue;
}
convert_glob_print_commit(&out);
if (!after_separator || *pattern != separator)
{
out.out_str[0] = CHAR_DOT;
out.out_str[1] = CHAR_ASTERISK;
out.out_str[2] = CHAR_QUESTION_MARK;
convert_glob_write_str(&out, 3);
continue;
}
out.out_str[0] = CHAR_LEFT_PARENTHESIS;
out.out_str[1] = CHAR_QUESTION_MARK;
out.out_str[2] = CHAR_COLON;
out.out_str[3] = CHAR_DOT;
out.out_str[4] = CHAR_ASTERISK;
out.out_str[5] = CHAR_QUESTION_MARK;
convert_glob_write_str(&out, 6);
convert_glob_print_separator(&out, separator, with_escape);
out.out_str[0] = CHAR_RIGHT_PARENTHESIS;
out.out_str[1] = CHAR_QUESTION_MARK;
out.out_str[2] = CHAR_QUESTION_MARK;
convert_glob_write_str(&out, 3);
pattern++;
continue;
}
if (pattern < pattern_end && *pattern == CHAR_ASTERISK)
{
do pattern++; while (pattern < pattern_end &&
*pattern == CHAR_ASTERISK);
}
if (no_wildsep)
{
if (pattern >= pattern_end)
{
no_slash_z = TRUE;
break;
}
if (is_start) continue;
}
if (!is_start)
{
if (after_starstar)
{
out.out_str[0] = CHAR_LEFT_PARENTHESIS;
out.out_str[1] = CHAR_QUESTION_MARK;
out.out_str[2] = CHAR_GREATER_THAN_SIGN;
convert_glob_write_str(&out, 3);
in_atomic = TRUE;
}
else
convert_glob_print_commit(&out);
}
if (no_wildsep)
convert_glob_write(&out, CHAR_DOT);
else
convert_glob_print_wildcard(&out, separator, with_escape);
out.out_str[0] = CHAR_ASTERISK;
out.out_str[1] = CHAR_QUESTION_MARK;
if (pattern >= pattern_end)
out.out_str[1] = CHAR_PLUS;
convert_glob_write_str(&out, 2);
continue;
}
if (c == CHAR_QUESTION_MARK)
{
if (no_wildsep)
convert_glob_write(&out, CHAR_DOT);
else
convert_glob_print_wildcard(&out, separator, with_escape);
continue;
}
if (c == CHAR_LEFT_SQUARE_BRACKET)
{
result = convert_glob_parse_range(&pattern, pattern_end,
&out, utf, separator, with_escape, escape, no_wildsep);
if (result != 0) break;
continue;
}
if (escape != 0 && c == escape)
{
if (pattern >= pattern_end)
{
result = PCRE2_ERROR_CONVERT_SYNTAX;
break;
}
c = *pattern++;
}
if (c < 128 && strchr(pcre2_escaped_literals, c) != NULL)
convert_glob_write(&out, CHAR_BACKSLASH);
convert_glob_write(&out, c);
}
if (result == 0)
{
if (!no_slash_z)
{
out.out_str[0] = CHAR_BACKSLASH;
out.out_str[1] = CHAR_z;
convert_glob_write_str(&out, 2);
}
if (in_atomic)
convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS);
convert_glob_write(&out, CHAR_NUL);
if (!dummyrun && out.output_size != (PCRE2_SIZE) (out.output - use_buffer))
result = PCRE2_ERROR_NOMEMORY;
}
if (result != 0)
{
*bufflenptr = pattern - pattern_start;
return result;
}
*bufflenptr = out.output_size - 1;
return 0;
}
PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
pcre2_pattern_convert(PCRE2_SPTR pattern, PCRE2_SIZE plength, uint32_t options,
PCRE2_UCHAR **buffptr, PCRE2_SIZE *bufflenptr,
pcre2_convert_context *ccontext)
{
int rc;
PCRE2_UCHAR dummy_buffer[DUMMY_BUFFER_SIZE];
PCRE2_UCHAR *use_buffer = dummy_buffer;
PCRE2_SIZE use_length = DUMMY_BUFFER_SIZE;
BOOL utf = (options & PCRE2_CONVERT_UTF) != 0;
uint32_t pattype = options & TYPE_OPTIONS;
if (pattern == NULL || bufflenptr == NULL) return PCRE2_ERROR_NULL;
if ((options & ~ALL_OPTIONS) != 0 ||
(pattype & (~pattype+1)) != pattype ||
pattype == 0)
{
*bufflenptr = 0;
return PCRE2_ERROR_BADOPTION;
}
if (plength == PCRE2_ZERO_TERMINATED) plength = PRIV(strlen)(pattern);
if (ccontext == NULL) ccontext =
(pcre2_convert_context *)(&PRIV(default_convert_context));
#ifndef SUPPORT_UNICODE
if (utf)
{
*bufflenptr = 0;
return PCRE2_ERROR_UNICODE_NOT_SUPPORTED;
}
#else
if (utf && (options & PCRE2_CONVERT_NO_UTF_CHECK) == 0)
{
PCRE2_SIZE erroroffset;
rc = PRIV(valid_utf)(pattern, plength, &erroroffset);
if (rc != 0)
{
*bufflenptr = erroroffset;
return rc;
}
}
#endif
if (buffptr != NULL && *buffptr != NULL)
{
use_buffer = *buffptr;
use_length = *bufflenptr;
}
for (int i = 0; i < 2; i++)
{
PCRE2_UCHAR *allocated;
BOOL dummyrun = buffptr == NULL || *buffptr == NULL;
switch(pattype)
{
case PCRE2_CONVERT_GLOB:
rc = convert_glob(options & ~PCRE2_CONVERT_GLOB, pattern, plength, utf,
use_buffer, use_length, bufflenptr, dummyrun, ccontext);
break;
case PCRE2_CONVERT_POSIX_BASIC:
case PCRE2_CONVERT_POSIX_EXTENDED:
rc = convert_posix(pattype, pattern, plength, utf, use_buffer, use_length,
bufflenptr, dummyrun, ccontext);
break;
default:
goto EXIT;
}
if (rc != 0 ||
buffptr == NULL ||
*buffptr != NULL)
return rc;
allocated = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
(*bufflenptr + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)ccontext);
if (allocated == NULL) return PCRE2_ERROR_NOMEMORY;
*buffptr = (PCRE2_UCHAR *)(((char *)allocated) + sizeof(pcre2_memctl));
use_buffer = *buffptr;
use_length = *bufflenptr + 1;
}
PCRE2_DEBUG_UNREACHABLE();
EXIT:
*bufflenptr = 0;
return PCRE2_ERROR_INTERNAL;
}
PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
pcre2_converted_pattern_free(PCRE2_UCHAR *converted)
{
if (converted != NULL)
{
pcre2_memctl *memctl =
(pcre2_memctl *)((char *)converted - sizeof(pcre2_memctl));
memctl->free(memctl, memctl->memory_data);
}
}