Add RegularExpressionDxe driver. Add RegExLib library header and sample implementation SlreRegExLib, based on open-source SLRE library (old version with permissive license).
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jonathan Doman <jonathan.do...@hp.com> --- MdeModulePkg/Include/Library/RegExLib.h | 165 +++++ MdeModulePkg/Library/SlreRegExLib/SLRE/License.txt | 9 + .../Library/SlreRegExLib/SLRE/SlreUefiPort.h | 31 + MdeModulePkg/Library/SlreRegExLib/SLRE/slre.c | 684 +++++++++++++++++++++ MdeModulePkg/Library/SlreRegExLib/SLRE/slre.h | 104 ++++ MdeModulePkg/Library/SlreRegExLib/SlreRegExLib.c | 301 +++++++++ MdeModulePkg/Library/SlreRegExLib/SlreRegExLib.inf | 38 ++ MdeModulePkg/MdeModulePkg.dec | 3 + MdeModulePkg/MdeModulePkg.dsc | 2 + .../RegularExpressionDxe/RegularExpressionDxe.c | 306 +++++++++ .../RegularExpressionDxe/RegularExpressionDxe.inf | 44 ++ 11 files changed, 1687 insertions(+) create mode 100644 MdeModulePkg/Include/Library/RegExLib.h create mode 100644 MdeModulePkg/Library/SlreRegExLib/SLRE/License.txt create mode 100644 MdeModulePkg/Library/SlreRegExLib/SLRE/SlreUefiPort.h create mode 100644 MdeModulePkg/Library/SlreRegExLib/SLRE/slre.c create mode 100644 MdeModulePkg/Library/SlreRegExLib/SLRE/slre.h create mode 100644 MdeModulePkg/Library/SlreRegExLib/SlreRegExLib.c create mode 100644 MdeModulePkg/Library/SlreRegExLib/SlreRegExLib.inf create mode 100644 MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.c create mode 100644 MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf diff --git a/MdeModulePkg/Include/Library/RegExLib.h b/MdeModulePkg/Include/Library/RegExLib.h new file mode 100644 index 0000000..75c930d --- /dev/null +++ b/MdeModulePkg/Include/Library/RegExLib.h @@ -0,0 +1,165 @@ +/** @file + + Regular Expression Library Class + + Copyright (c) 2014-2015, Hewlett-Packard Development Company, L.P. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License that accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ +#ifndef REG_EX_LIB_H +#define REG_EX_LIB_H + +#include <Uefi.h> + +typedef VOID* REG_EX_HANDLE; + +/** + Container for returning information about subexpression captures resulting + from successful matches. +**/ +typedef struct { + CONST CHAR8 *Ptr; ///< Beginning of captured subexpression within matched string. + INT32 Length; ///< Length of captured subexpression. +} REG_EX_CAPTURE; + +/** + Compile a regular expression in preparation for matching with RegExMatch. + A call to RegExFree is always required to free resources regardless of + whether compilation was successful. + + @param[out] Handle Pointer to RegExHandle to initialize. Must be freed + with a call to RegExFree when no longer needed. + @param[in] Pattern Pointer to null-terminated ASCII string containing + the desired regular expression. + + @return EFI_SUCCESS Operation was successful. + EFI_ABORTED Pattern could not be compiled. More information + may be found through RegExErrorMessage. + EFI_INVALID_PARAMETER A required parameter was NULL. + EFI_OUT_OF_RESOURCES Memory allocation failed. +**/ +EFI_STATUS +EFIAPI +RegExCompile ( + OUT REG_EX_HANDLE *Handle, + IN CONST CHAR8 *Pattern + ); + +/** + Search the input string for anything that matches the regular expression. + + Be aware that the specific implementation of this library class may not + support all regular expression syntax, which could lead to unexpected results. + + If no match is found, the contents of Captures is undefined (i.e. it may be + overwritten with invalid data). + + @param[in] Handle The compiled regular expression. + @param[in] String Pointer to null-terminated ASCII string to match + against the regular expression. + @param[out] Captures Pointer to array of REG_EX_CAPTURE objects to receive + the captured groups in the event of a match. According + to convention, the full (sub-)string match is put in + Captures[0], and the results of N capturing groups are + put in Captures[1:N]. The caller must allocate the + appropriate sized array (N+1). This parameter is optional + and may be NULL. + @param[in] NumCaptures Number of elements in the Captures array. If Captures + is NULL, this should be zero. + + @return TRUE Match was found. + FALSE No match was found. +**/ +BOOLEAN +EFIAPI +RegExMatch ( + IN REG_EX_HANDLE Handle, + IN CONST CHAR8 *String, + OUT REG_EX_CAPTURE Captures[], OPTIONAL + IN INT32 NumCaptures + ); + +/** + Free any resources associated with this regular expression when it's no + longer needed. + + @param[in] Handle Handle to regular expression to be freed. +**/ +VOID +EFIAPI +RegExFree ( + IN REG_EX_HANDLE Handle + ); + +/** + When compilation fails, the internal implementation may generate an error + string which can be read with this function. However, there may not always + be an error message when it seems like there should be, as this depends + on the specific implementation. + + @param[in] Handle Handle to regular expression. + + @return Pointer to null-terminated ASCII error message. May be NULL or + an empty string if there is no applicable error. +**/ +CONST CHAR8* +EFIAPI +RegExErrorMessage ( + IN REG_EX_HANDLE Handle + ); + +/** + Helper function. Match the string against a regex pattern. + + @param[in] String The string to check. + @param[in] Pattern The regex pattern. + + @retval TRUE The string matches the pattern. + @retval FALSE The string does not match the pattern. +**/ +BOOLEAN +RegExMatchString ( + IN CONST CHAR16 *String, + IN CONST CHAR8 *AsciiPattern + ); + +/** + Match the string against a regex pattern. + + @param[in] AnsiString The string to check. + @param[in] AnsiPattern The regex pattern. + + @retval TRUE The string matches the pattern. + @retval FALSE The string does not match the pattern. +**/ +BOOLEAN +RegExMatchStringAscii ( + IN CONST CHAR8 *AsciiString, + IN CONST CHAR8 *AsciiPattern + ); + +/** + Match the string against a regex pattern. + + If you happen to have a UCS-2 pattern string, this helper function will do + the ASCII conversion for you. + + @param[in] String The string to check. + @param[in] Pattern The regex pattern. + + @retval TRUE The string matches the pattern. + @retval FALSE The string does not match the pattern. +**/ +BOOLEAN +RegExMatchStringUnicode ( + IN CONST CHAR16 *String, + IN CONST CHAR16 *Pattern + ); + +#endif // !REG_EX_LIB_H diff --git a/MdeModulePkg/Library/SlreRegExLib/SLRE/License.txt b/MdeModulePkg/Library/SlreRegExLib/SLRE/License.txt new file mode 100644 index 0000000..fb0df8f --- /dev/null +++ b/MdeModulePkg/Library/SlreRegExLib/SLRE/License.txt @@ -0,0 +1,9 @@ +http://slre.sourceforge.net/ + +Copyright (c) 2004-2005 Sergey Lyubka <vale...@gmail.com> +All rights reserved + +"THE BEER-WARE LICENSE" (Revision 42): +Sergey Lyubka wrote this file. As long as you retain this notice you +can do whatever you want with this stuff. If we meet some day, and you think +this stuff is worth it, you can buy me a beer in return. diff --git a/MdeModulePkg/Library/SlreRegExLib/SLRE/SlreUefiPort.h b/MdeModulePkg/Library/SlreRegExLib/SLRE/SlreUefiPort.h new file mode 100644 index 0000000..e7389d8 --- /dev/null +++ b/MdeModulePkg/Library/SlreRegExLib/SLRE/SlreUefiPort.h @@ -0,0 +1,31 @@ +/** + @file + + Header to rewrite stdlib references within slre + + Copyright (c) 2014-2015, Hewlett-Packard Development Company, L.P.<BR> + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License that accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ +#ifndef SLRE_UEFI_PORT_H +#define SLRE_UEFI_PORT_H + +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> + +#define assert(x) ASSERT(x); +#define strchr(str,c) ScanMem8(str,sizeof(str),c) +#define memmove(dest,src,len) CopyMem(dest,src,len) +#define memcmp(dest,src,len) CompareMem(dest,src,len) +#define printf(...) + +#define isdigit(c) ((c) >= '0' && (c) <= '9') +#define isspace(c) ((c) == '\t' || (c) == '\n' || (c) == '\v' || (c) == 0xc || (c) == '\r' || (c) == ' ') + +#endif // !SLRE_UEFI_PORT_H diff --git a/MdeModulePkg/Library/SlreRegExLib/SLRE/slre.c b/MdeModulePkg/Library/SlreRegExLib/SLRE/slre.c new file mode 100644 index 0000000..ecb3d30 --- /dev/null +++ b/MdeModulePkg/Library/SlreRegExLib/SLRE/slre.c @@ -0,0 +1,684 @@ +/** + Copyright (c) 2014-2015, Hewlett-Packard Development Company, L.P.<BR> + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License that accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Copyright (c) 2004-2005 Sergey Lyubka <vale...@gmail.com> + All rights reserved + + "THE BEER-WARE LICENSE" (Revision 42): + Sergey Lyubka wrote this file. As long as you retain this notice you + can do whatever you want with this stuff. If we meet some day, and you think + this stuff is worth it, you can buy me a beer in return. +**/ + +#if 0 +#include <stdio.h> +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#endif + +#include "slre.h" + +enum {END, BRANCH, ANY, EXACT, ANYOF, ANYBUT, OPEN, CLOSE, BOL, EOL, + STAR, PLUS, STARQ, PLUSQ, QUEST, SPACE, NONSPACE, DIGIT}; + +#if 0 +static struct { + const char *name; + int narg; + const char *flags; +} opcodes[] = { + {"END", 0, ""}, /* End of code block or program */ + {"BRANCH", 2, "oo"}, /* Alternative operator, "|" */ + {"ANY", 0, ""}, /* Match any character, "." */ + {"EXACT", 2, "d"}, /* Match exact string */ + {"ANYOF", 2, "D"}, /* Match any from set, "[]" */ + {"ANYBUT", 2, "D"}, /* Match any but from set, "[^]"*/ + {"OPEN ", 1, "i"}, /* Capture start, "(" */ + {"CLOSE", 1, "i"}, /* Capture end, ")" */ + {"BOL", 0, ""}, /* Beginning of string, "^" */ + {"EOL", 0, ""}, /* End of string, "$" */ + {"STAR", 1, "o"}, /* Match zero or more times "*" */ + {"PLUS", 1, "o"}, /* Match one or more times, "+" */ + {"STARQ", 1, "o"}, /* Non-greedy STAR, "*?" */ + {"PLUSQ", 1, "o"}, /* Non-greedy PLUS, "+?" */ + {"QUEST", 1, "o"}, /* Match zero or one time, "?" */ + {"SPACE", 0, ""}, /* Match whitespace, "\s" */ + {"NONSPACE", 0, ""}, /* Match non-space, "\S" */ + {"DIGIT", 0, ""} /* Match digit, "\d" */ +}; +#endif + +/* + * Commands and operands are all unsigned char (1 byte long). All code offsets + * are relative to current address, and positive (always point forward). Data + * offsets are absolute. Commands with operands: + * + * BRANCH offset1 offset2 + * Try to match the code block that follows the BRANCH instruction + * (code block ends with END). If no match, try to match code block that + * starts at offset1. If either of these match, jump to offset2. + * + * EXACT data_offset data_length + * Try to match exact string. String is recorded in data section from + * data_offset, and has length data_length. + * + * OPEN capture_number + * CLOSE capture_number + * If the user have passed 'struct cap' array for captures, OPEN + * records the beginning of the matched substring (cap->ptr), CLOSE + * sets the length (cap->len) for respective capture_number. + * + * STAR code_offset + * PLUS code_offset + * QUEST code_offset + * *, +, ?, respectively. Try to gobble as much as possible from the + * matched buffer, until code block that follows these instructions + * matches. When the longest possible string is matched, + * jump to code_offset + * + * STARQ, PLUSQ are non-greedy versions of STAR and PLUS. + */ + +static const char *meta_chars = "|.^$*+?()[\\"; + +#if 0 +static void +print_character_set(FILE *fp, const unsigned char *p, int len) +{ + int i; + + for (i = 0; i < len; i++) { + if (i > 0) + (void) fputc(',', fp); + if (p[i] == 0) { + i++; + if (p[i] == 0) + (void) fprintf(fp, "\\x%02x", p[i]); + else + (void) fprintf(fp, "%s", opcodes[p[i]].name); + } else if (isprint(p[i])) { + (void) fputc(p[i], fp); + } else { + (void) fprintf(fp,"\\x%02x", p[i]); + } + } +} + +void +slre_dump(const struct slre *r, FILE *fp) +{ + int i, j, ch, op, pc; + + for (pc = 0; pc < r->code_size; pc++) { + + op = r->code[pc]; + (void) fprintf(fp, "%3d %s ", pc, opcodes[op].name); + + for (i = 0; opcodes[op].flags[i] != '\0'; i++) + switch (opcodes[op].flags[i]) { + case 'i': + (void) fprintf(fp, "%d ", r->code[pc + 1]); + pc++; + break; + case 'o': + (void) fprintf(fp, "%d ", + pc + r->code[pc + 1] - i); + pc++; + break; + case 'D': + print_character_set(fp, r->data + + r->code[pc + 1], r->code[pc + 2]); + pc += 2; + break; + case 'd': + (void) fputc('"', fp); + for (j = 0; j < r->code[pc + 2]; j++) { + ch = r->data[r->code[pc + 1] + j]; + if (isprint(ch)) + (void) fputc(ch, fp); + else + (void) fprintf(fp,"\\x%02x",ch); + } + (void) fputc('"', fp); + pc += 2; + break; + } + + (void) fputc('\n', fp); + } +} +#endif + +static void +set_jump_offset(struct slre *r, int pc, int offset) +{ + assert(offset < r->code_size); + + if (r->code_size - offset > 0xff) { + r->err_str = "Jump offset is too big"; + } else { + r->code[pc] = (unsigned char) (r->code_size - offset); + } +} + +static void +emit(struct slre *r, int code) +{ + if (r->code_size >= (int) (sizeof(r->code) / sizeof(r->code[0]))) + r->err_str = "RE is too long (code overflow)"; + else + r->code[r->code_size++] = (unsigned char) code; +} + +static void +store_char_in_data(struct slre *r, int ch) +{ + if (r->data_size >= (int) sizeof(r->data)) + r->err_str = "RE is too long (data overflow)"; + else + r->data[r->data_size++] = (unsigned char)ch; +} + +static void +exact(struct slre *r, const char **re) +{ + int old_data_size = r->data_size; + + while (**re != '\0' && (strchr(meta_chars, **re)) == NULL) + store_char_in_data(r, *(*re)++); + + emit(r, EXACT); + emit(r, old_data_size); + emit(r, r->data_size - old_data_size); +} + +static int +get_escape_char(const char **re) +{ + int res; + + switch (*(*re)++) { + case 'n': res = '\n'; break; + case 'r': res = '\r'; break; + case 't': res = '\t'; break; + case '0': res = 0; break; + case 'S': res = NONSPACE << 8; break; + case 's': res = SPACE << 8; break; + case 'd': res = DIGIT << 8; break; + default: res = (*re)[-1]; break; + } + + return (res); +} + +static void +anyof(struct slre *r, const char **re) +{ + int esc, old_data_size = r->data_size, op = ANYOF; + + if (**re == '^') { + op = ANYBUT; + (*re)++; + } + + while (**re != '\0') + + switch (*(*re)++) { + case ']': + emit(r, op); + emit(r, old_data_size); + emit(r, r->data_size - old_data_size); + return; + /* NOTREACHED */ + break; + case '\\': + esc = get_escape_char(re); + if ((esc & 0xff) == 0) { + store_char_in_data(r, 0); + store_char_in_data(r, esc >> 8); + } else { + store_char_in_data(r, esc); + } + break; + default: + store_char_in_data(r, (*re)[-1]); + break; + } + + r->err_str = "No closing ']' bracket"; +} + +static void +relocate(struct slre *r, int begin, int shift) +{ + emit(r, END); + memmove(r->code + begin + shift, r->code + begin, r->code_size - begin); + r->code_size += shift; +} + +static void +quantifier(struct slre *r, int prev, int op) +{ + if (r->code[prev] == EXACT && r->code[prev + 2] > 1) { + r->code[prev + 2]--; + emit(r, EXACT); + emit(r, r->code[prev + 1] + r->code[prev + 2]); + emit(r, 1); + prev = r->code_size - 3; + } + relocate(r, prev, 2); + r->code[prev] = (unsigned char)op; + set_jump_offset(r, prev + 1, prev); +} + +static void +exact_one_char(struct slre *r, int ch) +{ + emit(r, EXACT); + emit(r, r->data_size); + emit(r, 1); + store_char_in_data(r, ch); +} + +static void +fixup_branch(struct slre *r, int fixup) +{ + if (fixup > 0) { + emit(r, END); + set_jump_offset(r, fixup, fixup - 2); + } +} + +static void +compile(struct slre *r, const char **re) +{ + int op, esc, branch_start, last_op, fixup, cap_no, level; + + fixup = 0; + level = r->num_caps; + branch_start = last_op = r->code_size; + + for (;;) + switch (*(*re)++) { + case '\0': + (*re)--; + return; + /* NOTREACHED */ + break; + case '^': + emit(r, BOL); + break; + case '$': + emit(r, EOL); + break; + case '.': + last_op = r->code_size; + emit(r, ANY); + break; + case '[': + last_op = r->code_size; + anyof(r, re); + break; + case '\\': + last_op = r->code_size; + esc = get_escape_char(re); + if (esc & 0xff00) { + emit(r, esc >> 8); + } else { + exact_one_char(r, esc); + } + break; + case '(': + last_op = r->code_size; + cap_no = ++r->num_caps; + emit(r, OPEN); + emit(r, cap_no); + + compile(r, re); + if (*(*re)++ != ')') { + r->err_str = "No closing bracket"; + return; + } + + emit(r, CLOSE); + emit(r, cap_no); + break; + case ')': + (*re)--; + fixup_branch(r, fixup); + if (level == 0) { + r->err_str = "Unbalanced brackets"; + return; + } + return; + /* NOTREACHED */ + break; + case '+': + case '*': + op = (*re)[-1] == '*' ? STAR: PLUS; + if (**re == '?') { + (*re)++; + op = op == STAR ? STARQ : PLUSQ; + } + quantifier(r, last_op, op); + break; + case '?': + quantifier(r, last_op, QUEST); + break; + case '|': + fixup_branch(r, fixup); + relocate(r, branch_start, 3); + r->code[branch_start] = BRANCH; + set_jump_offset(r, branch_start + 1, branch_start); + fixup = branch_start + 2; + r->code[fixup] = 0xff; + break; + default: + (*re)--; + last_op = r->code_size; + exact(r, re); + break; + } +} + +int +slre_compile(struct slre *r, const char *re) +{ + r->err_str = NULL; + r->code_size = r->data_size = r->num_caps = r->anchored = 0; + + if (*re == '^') + r->anchored++; + + emit(r, OPEN); /* This will capture what matches full RE */ + emit(r, 0); + + while (*re != '\0') + compile(r, &re); + + if (r->code[2] == BRANCH) + fixup_branch(r, 4); + + emit(r, CLOSE); + emit(r, 0); + emit(r, END); + + return (r->err_str == NULL ? 1 : 0); +} + +static int match(const struct slre *, int, + const char *, int, int *, struct cap *); + +static void +loop_greedy(const struct slre *r, int pc, const char *s, int len, int *ofs) +{ + int saved_offset, matched_offset; + + saved_offset = matched_offset = *ofs; + + while (match(r, pc + 2, s, len, ofs, NULL)) { + saved_offset = *ofs; + if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL)) + matched_offset = saved_offset; + *ofs = saved_offset; + } + + *ofs = matched_offset; +} + +static void +loop_non_greedy(const struct slre *r, int pc, const char *s,int len, int *ofs) +{ + int saved_offset = *ofs; + + while (match(r, pc + 2, s, len, ofs, NULL)) { + saved_offset = *ofs; + if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL)) + break; + } + + *ofs = saved_offset; +} + +static int +is_any_of(const unsigned char *p, int len, const char *s, int *ofs) +{ + int i, ch; + + ch = s[*ofs]; + + for (i = 0; i < len; i++) + if (p[i] == ch) { + (*ofs)++; + return (1); + } + + return (0); +} + +static int +is_any_but(const unsigned char *p, int len, const char *s, int *ofs) +{ + int i, ch; + + ch = s[*ofs]; + + for (i = 0; i < len; i++) + if (p[i] == ch) + return (0); + + (*ofs)++; + return (1); +} + +static int +match(const struct slre *r, int pc, const char *s, int len, + int *ofs, struct cap *caps) +{ + int n, saved_offset, res = 1; + + while (res && r->code[pc] != END) { + + assert(pc < r->code_size); + assert(pc < (int) (sizeof(r->code) / sizeof(r->code[0]))); + + switch (r->code[pc]) { + case BRANCH: + saved_offset = *ofs; + res = match(r, pc + 3, s, len, ofs, caps); + if (res == 0) { + *ofs = saved_offset; + res = match(r, pc + r->code[pc + 1], + s, len, ofs, caps); + } + pc += r->code[pc + 2]; + break; + case EXACT: + res = 0; + n = r->code[pc + 2]; /* String length */ + if (n <= len - *ofs && !memcmp(s + *ofs, r->data + + r->code[pc + 1], n)) { + (*ofs) += n; + res = 1; + } + pc += 3; + break; + case QUEST: + res = 1; + saved_offset = *ofs; + if (!match(r, pc + 2, s, len, ofs, caps)) + *ofs = saved_offset; + pc += r->code[pc + 1]; + break; + case STAR: + res = 1; + loop_greedy(r, pc, s, len, ofs); + pc += r->code[pc + 1]; + break; + case STARQ: + res = 1; + loop_non_greedy(r, pc, s, len, ofs); + pc += r->code[pc + 1]; + break; + case PLUS: + if ((res = match(r, pc + 2, s, len, ofs, caps)) == 0) + break; + + loop_greedy(r, pc, s, len, ofs); + pc += r->code[pc + 1]; + break; + case PLUSQ: + if ((res = match(r, pc + 2, s, len, ofs, caps)) == 0) + break; + + loop_non_greedy(r, pc, s, len, ofs); + pc += r->code[pc + 1]; + break; + case SPACE: + res = 0; + if (*ofs < len && isspace(((unsigned char *)s)[*ofs])) { + (*ofs)++; + res = 1; + } + pc++; + break; + case NONSPACE: + res = 0; + if (*ofs <len && !isspace(((unsigned char *)s)[*ofs])) { + (*ofs)++; + res = 1; + } + pc++; + break; + case DIGIT: + res = 0; + if (*ofs < len && isdigit(((unsigned char *)s)[*ofs])) { + (*ofs)++; + res = 1; + } + pc++; + break; + case ANY: + res = 0; + if (*ofs < len) { + (*ofs)++; + res = 1; + } + pc++; + break; + case ANYOF: + res = 0; + if (*ofs < len) + res = is_any_of(r->data + r->code[pc + 1], + r->code[pc + 2], s, ofs); + pc += 3; + break; + case ANYBUT: + res = 0; + if (*ofs < len) + res = is_any_but(r->data + r->code[pc + 1], + r->code[pc + 2], s, ofs); + pc += 3; + break; + case BOL: + res = *ofs == 0 ? 1 : 0; + pc++; + break; + case EOL: + res = *ofs == len ? 1 : 0; + pc++; + break; + case OPEN: + if (caps != NULL) + caps[r->code[pc + 1]].ptr = s + *ofs; + pc += 2; + break; + case CLOSE: + if (caps != NULL) + caps[r->code[pc + 1]].len = (int)((s + *ofs) - caps[r->code[pc + 1]].ptr); + pc += 2; + break; + case END: + pc++; + break; + default: + printf("unknown cmd (%d) at %d\n", r->code[pc], pc); + assert(0); + break; + } + } + + return (res); +} + +int +slre_match(const struct slre *r, const char *buf, int len, + struct cap *caps) +{ + int i, ofs = 0, res = 0; + + if (r->anchored) { + res = match(r, 0, buf, len, &ofs, caps); + } else { + for (i = 0; i < len && res == 0; i++) { + ofs = i; + res = match(r, 0, buf, len, &ofs, caps); + } + } + + return (res); +} + +#if 0 +#ifdef TEST +int main(int argc, char *argv[]) +{ + struct slre slre; + struct cap caps[20]; + char data[1 * 1024 * 1024]; + FILE *fp; + int i, count, res, len; + + if (argc < 3) { + printf("Usage: %s 'slre' <file> [count]\n", argv[0]); + } else if ((fp = fopen(argv[2], "rb")) == NULL) { + printf("Error: cannot open %s:%s\n", argv[2], strerror(errno)); + } else if (!slre_compile(&slre, argv[1])) { + printf("Error compiling slre: %s\n", slre.err_str); + } else { + slre_dump(&slre, stderr); + + (void) memset(caps, 0, sizeof(caps)); + + /* Read first 128K of file */ + len = fread(data, 1, sizeof(data), fp); + (void) fclose(fp); + + res = 0; + count = argc > 3 ? atoi(argv[3]) : 1; + for (i = 0; i < count; i++) + res = slre_match(&slre, data, len, caps); + + printf("Result: %d\n", res); + + for (i = 0; i < 20; i++) + if (caps[i].len > 0) + printf("Substring %d: [%.*s]\n", i, + caps[i].len, caps[i].ptr); + } + + return (0); +} +#endif /* TEST */ +#endif diff --git a/MdeModulePkg/Library/SlreRegExLib/SLRE/slre.h b/MdeModulePkg/Library/SlreRegExLib/SLRE/slre.h new file mode 100644 index 0000000..9aecdd5 --- /dev/null +++ b/MdeModulePkg/Library/SlreRegExLib/SLRE/slre.h @@ -0,0 +1,104 @@ +/** + Copyright (c) 2014-2015, Hewlett-Packard Development Company, L.P.<BR> + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License that accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Copyright (c) 2004-2005 Sergey Lyubka <vale...@gmail.com> + All rights reserved + + "THE BEER-WARE LICENSE" (Revision 42): + Sergey Lyubka wrote this file. As long as you retain this notice you + can do whatever you want with this stuff. If we meet some day, and you think + this stuff is worth it, you can buy me a beer in return. +**/ + +/* + * This is a regular expression library that implements a subset of Perl RE. + * Please refer to http://slre.sourceforge.net for detailed description. + * + * Usage example (parsing HTTP request): + * + * struct slre slre; + * struct cap captures[4 + 1]; // Number of braket pairs + 1 + * ... + * + * slre_compile(&slre,"^(GET|POST) (\S+) HTTP/(\S+?)\r\n"); + * + * if (slre_match(&slre, buf, len, captures)) { + * printf("Request line length: %d\n", captures[0].len); + * printf("Method: %.*s\n", captures[1].len, captures[1].ptr); + * printf("URI: %.*s\n", captures[2].len, captures[2].ptr); + * } + * + * Supported syntax: + * ^ Match beginning of a buffer + * $ Match end of a buffer + * () Grouping and substring capturing + * [...] Match any character from set + * [^...] Match any character but ones from set + * \s Match whitespace + * \S Match non-whitespace + * \d Match decimal digit + * \r Match carriage return + * \n Match newline + * + Match one or more times (greedy) + * +? Match one or more times (non-greedy) + * * Match zero or more times (greedy) + * *? Match zero or more times (non-greedy) + * ? Match zero or once + * \xDD Match byte with hex value 0xDD + * \meta Match one of the meta character: ^$().[*+?\ + */ + +#ifndef SLRE_HEADER_DEFINED +#define SLRE_HEADER_DEFINED + +#include "SlreUefiPort.h" + +/* + * Compiled regular expression + */ +struct slre { + unsigned char code[256]; + unsigned char data[256]; + int code_size; + int data_size; + int num_caps; /* Number of bracket pairs */ + int anchored; /* Must match from string start */ + const char *err_str; /* Error string */ +}; + +/* + * Captured substring + */ +struct cap { + const char *ptr; /* Pointer to the substring */ + int len; /* Substring length */ +}; + +/* + * Compile regular expression. If success, 1 is returned. + * If error, 0 is returned and slre.err_str points to the error message. + */ +int slre_compile(struct slre *, const char *re); + +/* + * Return 1 if match, 0 if no match. + * If `captured_substrings' array is not NULL, then it is filled with the + * values of captured substrings. captured_substrings[0] element is always + * a full matched substring. The round bracket captures start from + * captured_substrings[1]. + * It is assumed that the size of captured_substrings array is enough to + * hold all captures. The caller function must make sure it is! So, the + * array_size = number_of_round_bracket_pairs + 1 + */ +int slre_match(const struct slre *, const char *buf, int buf_len, + struct cap *captured_substrings); + +#endif /* SLRE_HEADER_DEFINED */ diff --git a/MdeModulePkg/Library/SlreRegExLib/SlreRegExLib.c b/MdeModulePkg/Library/SlreRegExLib/SlreRegExLib.c new file mode 100644 index 0000000..a912595 --- /dev/null +++ b/MdeModulePkg/Library/SlreRegExLib/SlreRegExLib.c @@ -0,0 +1,301 @@ +/** + @file + + RegExLib implementation using SLRE + + Copyright (c) 2014-2015, Hewlett-Packard Development Company, L.P.<BR> + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License that accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include "SLRE/slre.h" + +#include <Uefi.h> + +#include <Library/RegExLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +typedef struct { + struct slre SlreState; + struct cap *SlreCaptures; + INT32 NumCaptures; +} SLRE_REG_EX_STATE; + +/** + Compile a regular expression in preparation for matching with RegExMatch. + A call to RegExFree is always required to free resources regardless of + whether compilation was successful. + + @param[out] Handle Pointer to RegExHandle to initialize. Must be freed + with a call to RegExFree when no longer needed. + @param[in] Pattern Pointer to null-terminated ASCII string containing + the desired regular expression. + + @return EFI_SUCCESS Operation was successful. + EFI_ABORTED Pattern could not be compiled. More information + may be found through RegExErrorMessage. + EFI_INVALID_PARAMETER A required parameter was NULL. + EFI_OUT_OF_RESOURCES Memory allocation failed. +**/ +EFI_STATUS +EFIAPI +RegExCompile ( + OUT REG_EX_HANDLE *Handle, + IN CONST CHAR8 *Pattern + ) +{ + INT32 Result; + SLRE_REG_EX_STATE *SlreRegEx; + + if (Handle == NULL || Pattern == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Handle = AllocatePool (sizeof(SLRE_REG_EX_STATE)); + if (*Handle == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SlreRegEx = *Handle; + SlreRegEx->SlreCaptures = NULL; + SlreRegEx->NumCaptures = 0; + + Result = slre_compile (&SlreRegEx->SlreState, Pattern); + + return (Result == 1) ? EFI_SUCCESS : EFI_ABORTED; +} + +/** + Search the input string for anything that matches the regular expression. + + Be aware that the specific implementation of this library class may not + support all regular expression syntax, which could lead to unexpected results. + + If no match is found, the contents of Captures is undefined (i.e. it may be + overwritten with invalid data). + + @param[in] Handle The compiled regular expression. + @param[in] String Pointer to null-terminated ASCII string to match + against the regular expression. + @param[out] Captures Pointer to array of REG_EX_CAPTURE objects to receive + the captured groups in the event of a match. According + to convention, the full (sub-)string match is put in + Captures[0], and the results of N capturing groups are + put in Captures[1:N]. The caller must allocate the + appropriate sized array (N+1). This parameter is optional + and may be NULL. + @param[in] NumCaptures Number of elements in the Captures array. If Captures + is NULL, this should be zero. + + @return TRUE Match was found. + FALSE No match was found. +**/ +BOOLEAN +EFIAPI +RegExMatch ( + IN REG_EX_HANDLE Handle, + IN CONST CHAR8 *String, + OUT REG_EX_CAPTURE Captures[], OPTIONAL + IN INT32 NumCaptures + ) +{ + SLRE_REG_EX_STATE *SlreHandle; + INT32 Return; + INT32 Index; + struct cap *SlreCaptures; + + SlreHandle = Handle; + + // + // Allocate internal captures buffer, same size as caller-provided buffer. + // Reuse across calls when possible. + // + if (Captures != NULL) { + if (SlreHandle->SlreCaptures != NULL && NumCaptures > SlreHandle->NumCaptures) { + FreePool (SlreHandle->SlreCaptures); + SlreHandle->SlreCaptures = NULL; + } + if (SlreHandle->SlreCaptures == NULL) { + SlreHandle->SlreCaptures = AllocateZeroPool (NumCaptures * sizeof(struct cap)); + ASSERT (SlreHandle->SlreCaptures != NULL); + } + SlreHandle->NumCaptures = NumCaptures; + SlreCaptures = SlreHandle->SlreCaptures; + } else { + ASSERT (NumCaptures == 0); + SlreCaptures = NULL; + } + + Return = slre_match (&SlreHandle->SlreState, String, (INT32)AsciiStrLen (String), SlreCaptures); + + // + // Translate internal captures into RegExLib standard captures + // + if (Return == 1) { + for (Index = 0; Index < NumCaptures; ++Index) { + Captures[Index].Ptr = SlreHandle->SlreCaptures[Index].ptr; + Captures[Index].Length = SlreHandle->SlreCaptures[Index].len; + } + } + + return (Return == 1); +} + +/** + Free any resources associated with this regular expression when it's no + longer needed. + + @param[in] Handle Handle to regular expression to be freed. +**/ +VOID +EFIAPI +RegExFree ( + IN REG_EX_HANDLE Handle + ) +{ + SLRE_REG_EX_STATE *SlreHandle; + + SlreHandle = Handle; + + if (SlreHandle != NULL) { + if (SlreHandle->SlreCaptures != NULL) { + FreePool (SlreHandle->SlreCaptures); + } + FreePool (Handle); + } +} + +/** + When compilation fails, the internal implementation may generate an error + string which can be read with this function. However, there may not always + be an error message when it seems like there should be, as this depends + on the specific implementation. + + @param[in] Handle Handle to regular expression. + + @return Pointer to null-terminated ASCII error message. May be NULL or + an empty string if there is no applicable error. +**/ +CONST CHAR8* +EFIAPI +RegExErrorMessage ( + IN REG_EX_HANDLE Handle + ) +{ + return ((SLRE_REG_EX_STATE*)Handle)->SlreState.err_str; +} + +/** + Match the string against a regex pattern. + + @param[in] AnsiString The string to check. + @param[in] AnsiPattern The regex pattern. + + @retval TRUE The string matches the pattern. + @retval FALSE The string does not match the pattern. +**/ +BOOLEAN +RegExMatchStringAscii ( + IN CONST CHAR8 *AnsiString, + IN CONST CHAR8 *AnsiPattern + ) +{ + REG_EX_HANDLE RegExHandle; + EFI_STATUS Status; + BOOLEAN Result; + + if ((AnsiString == NULL) || (AnsiPattern == NULL)) { + return FALSE; + } + + Status = RegExCompile (&RegExHandle, AnsiPattern); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SLRE RegEx Compile failed: %r, %a\n", Status, RegExErrorMessage (RegExHandle))); + Result = FALSE; + } else { + Result = RegExMatch (RegExHandle, AnsiString, NULL, 0); + } + + RegExFree (RegExHandle); + + return Result; +} + +/** + Match the string against a regex pattern. + + @param[in] String The string to check. + @param[in] Pattern The regex pattern. + + @retval TRUE The string matches the pattern. + @retval FALSE The string does not match the pattern. +**/ +BOOLEAN +RegExMatchString ( + IN CONST CHAR16 *String, + IN CONST CHAR8 *Pattern + ) +{ + BOOLEAN Result; + CHAR8 *AnsiStr; + + if ((String == NULL) || (Pattern == NULL)) { + return FALSE; + } + + AnsiStr = (CHAR8 *) AllocatePool ((StrLen (String) + 1) * sizeof (CHAR8)); + if (AnsiStr == NULL) { + return FALSE; + } + + UnicodeStrToAsciiStr (String, AnsiStr); + Result = RegExMatchStringAscii (AnsiStr, Pattern); + + FreePool (AnsiStr); + + return Result; +} + +/** + Match the string against a regex pattern. + + If you happen to have a UCS-2 pattern string, this helper function will do + the ASCII conversion for you. + + @param[in] String The string to check. + @param[in] Pattern The regex pattern. + + @retval TRUE The string matches the pattern. + @retval FALSE The string does not match the pattern. +**/ +BOOLEAN +RegExMatchStringUnicode ( + IN CONST CHAR16 *String, + IN CONST CHAR16 *Pattern + ) +{ + CHAR8 *AsciiPattern; + BOOLEAN Match; + + Match = FALSE; + + AsciiPattern = AllocatePool (StrLen (Pattern) + 1); + if (AsciiPattern == NULL) { + return FALSE; + } + UnicodeStrToAsciiStr (Pattern, AsciiPattern); + + Match = RegExMatchString (String, AsciiPattern); + + FreePool (AsciiPattern); + + return Match; +} diff --git a/MdeModulePkg/Library/SlreRegExLib/SlreRegExLib.inf b/MdeModulePkg/Library/SlreRegExLib/SlreRegExLib.inf new file mode 100644 index 0000000..a8a6710 --- /dev/null +++ b/MdeModulePkg/Library/SlreRegExLib/SlreRegExLib.inf @@ -0,0 +1,38 @@ +## +# @file +# +# RegExLib implementation using SLRE +# +# Copyright (c) 2014-2015, Hewlett-Packard Development Company, L.P.<BR> +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License that accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +## + +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = SlreRegExLib + FILE_GUID = 985CB64D-620A-4E45-B84D-E39C5536D76F + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RegExLib + +[Sources] + SlreRegExLib.c + SLRE/SlreUefiPort.h + SLRE/slre.h + SLRE/slre.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + BaseMemoryLib diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 93ae120..6b5d1ba 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -111,6 +111,9 @@ ## @libraryclass Provides core boot manager functions PlatformBootManagerLib|Include/Library/PlatformBootManagerLib.h + ## @libraryclass Regular expression matching + RegExLib|Include/Library/RegExLib.h + [Guids] ## MdeModule package token space guid # Include/Guid/MdeModulePkgTokenSpace.h diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index d0832bc..94ebbd8 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -95,6 +95,7 @@ S3BootScriptLib|MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf CpuExceptionHandlerLib|MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf PlatformBootManagerLib|MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf + RegExLib|MdeModulePkg/Library/SlreRegExLib/SlreRegExLib.inf [LibraryClasses.EBC.PEIM] IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf @@ -298,6 +299,7 @@ MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf + MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf diff --git a/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.c b/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.c new file mode 100644 index 0000000..57558c9 --- /dev/null +++ b/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.c @@ -0,0 +1,306 @@ +/** + @file + + EFI_REGULAR_EXPRESSION_PROTOCOL Implementation + + Copyright (c) 2015, Hewlett-Packard Development Company, L.P.<BR> + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License that accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include <Uefi.h> +#include <Protocol/RegularExpressionProtocol.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/RegExLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseLib.h> + +#define ARRAY_SIZE(Array) (sizeof(Array) / sizeof(*Array)) + +STATIC +EFI_REGEX_SYNTAX_TYPE * CONST mSupportedSyntaxes[] = { + &gEfiRegexSyntaxTypePosixExtendedGuid +}; + +/** + POSIX Extended regex syntax implementation. + + @ref RegularExpressionMatch +**/ +STATIC +EFI_STATUS +PosixExtendedMatch ( + IN CHAR16 *String, + IN CHAR16 *Pattern, + OUT BOOLEAN *Result, + OUT EFI_REGEX_CAPTURE **Captures, OPTIONAL + OUT UINTN *CapturesCount + ) +{ + REG_EX_HANDLE Regex; + CHAR8 *AsciiString; + CHAR8 *AsciiPattern; + EFI_STATUS Status; + + ASSERT (String != NULL); + ASSERT (Pattern != NULL); + ASSERT (Result != NULL); + ASSERT (CapturesCount != NULL); + + // + // Our POSIX Extended library only supports ASCII input + // + AsciiString = AllocatePool (StrLen (String) + 1); + if (AsciiString == NULL) { + return EFI_OUT_OF_RESOURCES; + } + UnicodeStrToAsciiStr (String, AsciiString); + + AsciiPattern = AllocatePool (StrLen (Pattern) + 1); + if (AsciiPattern == NULL) { + FreePool (AsciiString); + return EFI_OUT_OF_RESOURCES; + } + UnicodeStrToAsciiStr (Pattern, AsciiPattern); + + // + // Compile and run the regex + // + Status = RegExCompile (&Regex, AsciiPattern); + + if (!EFI_ERROR (Status)) { + *Result = RegExMatch (Regex, AsciiString, NULL, 0); + } else { + *Result = FALSE; + } + + // + // Write out the results + // + if (!*Result) { + if (Captures != NULL) { + *Captures = NULL; + } + *CapturesCount = 0; + } else { + // + // Doesn't support sub-expression capture groups yet + // + if (Captures != NULL) { + *Captures = AllocatePool (sizeof(EFI_REGEX_CAPTURE)); + (*Captures)[0].CapturePtr = String; + (*Captures)[0].Length = StrLen (String); + } + *CapturesCount = 1; + } + + RegExFree (Regex); + + FreePool (AsciiPattern); + FreePool (AsciiString); + + return Status; +} + +/** + Returns information about the regular expression syntax types supported + by the implementation. + + This A pointer to the EFI_REGULAR_EXPRESSION_PROTOCOL + instance. + + RegExSyntaxTypeListSize On input, the size in bytes of RegExSyntaxTypeList. + On output with a return code of EFI_SUCCESS, the + size in bytes of the data returned in + RegExSyntaxTypeList. On output with a return code + of EFI_BUFFER_TOO_SMALL, the size of + RegExSyntaxTypeList required to obtain the list. + + RegExSyntaxTypeList A caller-allocated memory buffer filled by the + driver with one EFI_REGEX_SYNTAX_TYPE element + for each supported Regular expression syntax + type. The list must not change across multiple + calls to the same driver. The first syntax + type in the list is the default type for the + driver. + + @retval EFI_SUCCESS The regular expression syntax types list + was returned successfully. + @retval EFI_UNSUPPORTED The service is not supported by this driver. + @retval EFI_DEVICE_ERROR The list of syntax types could not be + retrieved due to a hardware or firmware error. + @retval EFI_BUFFER_TOO_SMALL The buffer RegExSyntaxTypeList is too small + to hold the result. + @retval EFI_INVALID_PARAMETER RegExSyntaxTypeListSize is NULL + +**/ +EFI_STATUS +EFIAPI +RegularExpressionGetInfo ( + IN EFI_REGULAR_EXPRESSION_PROTOCOL *This, + IN OUT UINTN *RegExSyntaxTypeListSize, + OUT EFI_REGEX_SYNTAX_TYPE *RegExSyntaxTypeList + ) +{ + UINTN SyntaxSize; + UINTN Index; + + if (This == NULL || RegExSyntaxTypeListSize == NULL || RegExSyntaxTypeList == NULL) { + return EFI_INVALID_PARAMETER; + } + + SyntaxSize = ARRAY_SIZE (mSupportedSyntaxes) * sizeof(**mSupportedSyntaxes); + + if (*RegExSyntaxTypeListSize < SyntaxSize) { + *RegExSyntaxTypeListSize = SyntaxSize; + return EFI_BUFFER_TOO_SMALL; + } + + for (Index = 0; Index < ARRAY_SIZE (mSupportedSyntaxes); ++Index) { + CopyMem (&RegExSyntaxTypeList[Index], mSupportedSyntaxes[Index], sizeof(**mSupportedSyntaxes)); + } + *RegExSyntaxTypeListSize = SyntaxSize; + + return EFI_SUCCESS; +} + +/** + Checks if the input string matches to the regular expression pattern. + + This A pointer to the EFI_REGULAR_EXPRESSION_PROTOCOL instance. + Type EFI_REGULAR_EXPRESSION_PROTOCOL is defined in Section + XYZ. + + String A pointer to a NULL terminated string to match against the + regular expression string specified by Pattern. + + Pattern A pointer to a NULL terminated string that represents the + regular expression. + + SyntaxType A pointer to the EFI_REGEX_SYNTAX_TYPE that identifies the + regular expression syntax type to use. May be NULL in which + case the function will use its default regular expression + syntax type. + + Result On return, points to TRUE if String fully matches against + the regular expression Pattern using the regular expression + SyntaxType. Otherwise, points to FALSE. + + Captures A Pointer to an array of EFI_REGEX_CAPTURE objects to receive + the captured groups in the event of a match. The full + sub-string match is put in Captures[0], and the results of N + capturing groups are put in Captures[1:N]. If Captures is + NULL, then this function doesn't allocate the memory for the + array and does not build up the elements. It only returns the + number of matching patterns in CapturesCount. If Captures is + not NULL, this function returns a pointer to an array and + builds up the elements in the array. CapturesCount is also + updated to the number of matching patterns found. It is the + caller's responsibility to free the memory pool in Captures + and in each CapturePtr in the array elements. + + CapturesCount On output, CapturesCount is the number of matching patterns + found in String. Zero means no matching patterns were found + in the string. + + @retval EFI_SUCCESS The regular expression string matching + completed successfully. + @retval EFI_UNSUPPORTED The regular expression syntax specified by + SyntaxType is not supported by this driver. + @retval EFI_DEVICE_ERROR The regular expression string matching + failed due to a hardware or firmware error. + @retval EFI_INVALID_PARAMETER String, Pattern, Result, or CapturesCountis + NULL. + +**/ +EFI_STATUS +EFIAPI +RegularExpressionMatch ( + IN EFI_REGULAR_EXPRESSION_PROTOCOL *This, + IN CHAR16 *String, + IN CHAR16 *Pattern, + IN EFI_REGEX_SYNTAX_TYPE *SyntaxType, OPTIONAL + OUT BOOLEAN *Result, + OUT EFI_REGEX_CAPTURE **Captures, OPTIONAL + OUT UINTN *CapturesCount + ) +{ + EFI_STATUS Status; + UINT32 Index; + BOOLEAN Supported; + + if (This == NULL || String == NULL || Pattern == NULL || Result == NULL || CapturesCount == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Figure out which syntax to use + // + if (SyntaxType == NULL) { + SyntaxType = mSupportedSyntaxes[0]; + } else { + Supported = FALSE; + for (Index = 0; Index < ARRAY_SIZE (mSupportedSyntaxes); ++Index) { + if (CompareGuid (SyntaxType, mSupportedSyntaxes[Index])) { + Supported = TRUE; + break; + } + } + if (!Supported) { + return EFI_UNSUPPORTED; + } + } + + // + // Here is where we determine which underlying library can handle the + // requested syntax. (Or possibly one library can implement all the + // protocols.) + // + if (CompareGuid (SyntaxType, &gEfiRegexSyntaxTypePosixExtendedGuid)) { + Status = PosixExtendedMatch (String, Pattern, Result, Captures, CapturesCount); + } else { + ASSERT (FALSE); + DEBUG ((DEBUG_ERROR, "Regex Syntax %g is supported but unimplemented\n", SyntaxType)); + Status = EFI_DEVICE_ERROR; + } + + return Status; +} + +/** + Entry point for RegularExpressionDxe. +**/ +EFI_STATUS +EFIAPI +RegularExpressionDxeEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + STATIC + CONST EFI_REGULAR_EXPRESSION_PROTOCOL ProtocolInstance = { + RegularExpressionMatch, + RegularExpressionGetInfo + }; + + (VOID)SystemTable; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiRegularExpressionProtocolGuid, + &ProtocolInstance, + NULL + ); + + return Status; +} diff --git a/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf b/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf new file mode 100644 index 0000000..b83f105 --- /dev/null +++ b/MdeModulePkg/Universal/RegularExpressionDxe/RegularExpressionDxe.inf @@ -0,0 +1,44 @@ +## +# @file +# +# EFI_REGULAR_EXPRESSION_PROTOCOL Implementation +# +# Copyright (c) 2015, Hewlett-Packard Development Company, L.P.<BR> +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License that accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +## + +[Defines] + INF_VERSION = 0x00010018 + BASE_NAME = RegularExpressionDxe + FILE_GUID = 3E197E9C-D8DC-42D3-89CE-B04FA9833756 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = RegularExpressionDxeEntry + +[Sources] + RegularExpressionDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + MemoryAllocationLib + BaseMemoryLib + DebugLib + RegExLib + +[Guids] + gEfiRegexSyntaxTypePosixExtendedGuid + +[Protocols] + gEfiRegularExpressionProtocolGuid -- 2.4.1 ------------------------------------------------------------------------------ One dashboard for servers and applications across Physical-Virtual-Cloud Widest out-of-the-box monitoring support with 50+ applications Performance metrics, stats and reports that give you Actionable Insights Deep dive visibility with transaction tracing using APM Insight. http://ad.doubleclick.net/ddm/clk/290420510;117567292;y _______________________________________________ edk2-devel mailing list edk2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/edk2-devel