I will look into TRE. But regarding the protocol, EFI_REGULAR_EXPRESSION_PROTOCOL is already defined in MdePkg as part of UEFI 2.5 implementation. I think providing a sample implementation in MdeModulePkg is reasonable.
I agree on the commit splitting. ________________________________________ From: Jordan Justen [jordan.l.jus...@intel.com] Sent: Monday, May 25, 2015 15:36 To: edk2-devel@lists.sourceforge.net; Doman, Jonathan Subject: Re: [edk2] [PATCH v2] MdeModulePkg: Regular expression protocol On 2015-05-20 14:08:40, Jonathan Doman wrote: > Add RegularExpressionDxe driver. Add RegExLib library header and sample > implementation SlreRegExLib, based on open-source SLRE library (old > version with permissive license). I think you should mention "THE BEER-WARE LICENSE" (Revision 42) here. But, rather, how about trying instead to port this 2-clause BSD code? https://github.com/laurikari/tre/ I also wonder if this belongs in MdeModulePkg. Also, is a protocol appropriate? I guess if you are using it in various drivers in the firmware. I'm thinking this might be more valuable for applications, and thus I'm wondering if just a library interface and implementation in AppPkg might something to start with. Regarding the commits, I think they should be split: 1. Library interface 2. Protocol interface 3. Library implementation 4. Dxe driver -Jordan > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Jonathan Doman <jonathan.do...@hp.com> > --- > v2 changes: > * Fix use of variadic macro and strchr define > > 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..94bcf7d > --- /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> > +#include <Library/BaseLib.h> > + > +#define assert(x) ASSERT(x); > +#define strchr(str,c) ScanMem8(str,AsciiStrSize(str),c) > +#define memmove(dest,src,len) CopyMem(dest,src,len) > +#define memcmp(dest,src,len) CompareMem(dest,src,len) > + > +#define isdigit(c) ((c) >= '0' && (c) <= '9') > +#define isspace(c) ((c) == ' ' || (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..041931f > --- /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 = ' '; 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 ------------------------------------------------------------------------------ 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