On 2015-05-22 09:27:47, Doman, Jonathan wrote:
> 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.

Since the protocol didn't define re compiles, should the library? I
would say no.

This actually seems like a pretty big issue with the protocol
definition, but it is too late for discussing that.

I think the library should be able to be implemented as a thin layer
on top of the protocol.

> 2. No reason other than the fact that Unicode is not supported by
> any of our implementations.

Does it match the spec then?

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

Since the protoco defined it as CHAR16*, I think we'd need to support
UTF-16 chars in the 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.

I agree that the library could have Ascii wrappers to the unicode
versions.

-Jordan

> 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) == '    ' || (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 = '    ';             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

------------------------------------------------------------------------------
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to