Jonathan,
I still suggest to only use CHAR16 in the library interface. That can make it 
possible for future another Regex library implementation supports CHAR16 
pattern. Your implementation can check the PATTERN and return UNSUPPORTED when 
the CHAR16 PATTERN contains non-ASCII character.
With the CHAR16 INPUT and CHAR16 PATTERN, we can just provide a UNICODE version 
of RegexMatchString(...).

Regarding the error message, I agree to directly return a 
caller-responsible-free error string from RegexCompile and not create a handle 
upon a failure.

Thanks,
Ray

-----Original Message-----
From: Doman, Jonathan [mailto:jonathan.do...@hp.com] 
Sent: Saturday, May 23, 2015 12:28 AM
To: edk2-devel@lists.sourceforge.net
Subject: Re: [edk2] [PATCH] MdeModulePkg: Regular expression protocol

Hi Ray, thanks for the feedback.

1. As you noticed, a valid handle is always returned whenever possible so that 
an error message can be retrieved. But this does complicate things, since 
RegExFree must then be called on all paths. I suppose a better solution might 
be to return a pointer to an error string directly from RegExCompile, and not 
create a handle upon failure.

2. No reason other than the fact that Unicode is not supported by any of our 
implementations. I can change it to accept CHAR16 input strings. What do you 
think about the pattern itself? I don't see much use for CHAR16 patterns.

3. We have many different use cases so the wrapper functions simplified things. 
If you only want to keep one, which is the most useful? I would like to keep 
CHAR16/CHAR8 (input/pattern) at least.

4. Agreed.
________________________________________
From: Ni, Ruiyu [ruiyu...@intel.com]
Sent: Friday, May 22, 2015 01:15
To: edk2-devel@lists.sourceforge.net
Subject: Re: [edk2] [PATCH] MdeModulePkg: Regular expression protocol

4. how about Regex instead of RegEx? C# uses Regex name.

-----Original Message-----
From: Ni, Ruiyu [mailto:ruiyu...@intel.com]
Sent: Friday, May 22, 2015 1:29 PM
To: edk2-devel@lists.sourceforge.net
Subject: Re: [edk2] [PATCH] MdeModulePkg: Regular expression protocol

Doman,
1. If RegExCompile() returns ABORTED, is the HANDLE valid or not? Because of 
ABORTED, it makes more sense to let HANDLE to not be created. But then 
RegExErrorMessage(HANDLE) cannot be called.

2. Why do you use CHAR8 instead of CHAR16 for captured string? Even your 
library implementation just supports ASCII encoding, the interface should be 
able to accept CHAR16.

3. Why do you introduce different versions of RegExMatchStringXXX()? BaseLib 
contains UnicodeStrToAsciiStr()/AsciiStrToUnicodeStr() and caller can use them 
to do conversion before calling RegExMatchString(). I suggest we use CHAR16 and 
only accepts CHAR16. CHAR8 string needs be converted by caller before calling 
into RegEx library.

Thanks,
Ray

-----Original Message-----
From: Jonathan Doman [mailto:jonathan.do...@hp.com]
Sent: Thursday, May 21, 2015 1:57 AM
To: edk2-devel@lists.sourceforge.net
Subject: [edk2] [PATCH] MdeModulePkg: Regular expression protocol

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

------------------------------------------------------------------------------
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

------------------------------------------------------------------------------
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

Reply via email to