Home | History | Annotate | Download | only in RegularExpressionDxe
      1 /** @file
      2 
      3   EFI_REGULAR_EXPRESSION_PROTOCOL Implementation
      4 
      5   (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
      6 
      7   This program and the accompanying materials are licensed and made available
      8   under the terms and conditions of the BSD License that accompanies this
      9   distribution.  The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php.
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
     13   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "RegularExpressionDxe.h"
     18 
     19 STATIC
     20 EFI_REGEX_SYNTAX_TYPE * CONST mSupportedSyntaxes[] = {
     21   &gEfiRegexSyntaxTypePosixExtendedGuid,
     22   &gEfiRegexSyntaxTypePerlGuid
     23 };
     24 
     25 STATIC
     26 EFI_REGULAR_EXPRESSION_PROTOCOL mProtocolInstance = {
     27   RegularExpressionMatch,
     28   RegularExpressionGetInfo
     29 };
     30 
     31 
     32 
     33 #define CHAR16_ENCODING ONIG_ENCODING_UTF16_LE
     34 
     35 /**
     36   Call the Oniguruma regex match API.
     37 
     38   Same parameters as RegularExpressionMatch, except SyntaxType is required.
     39 
     40   @param String         A pointer to a NULL terminated string to match against the
     41                         regular expression string specified by Pattern.
     42 
     43   @param Pattern        A pointer to a NULL terminated string that represents the
     44                         regular expression.
     45   @param SyntaxType     A pointer to the EFI_REGEX_SYNTAX_TYPE that identifies the
     46                         regular expression syntax type to use. May be NULL in which
     47                         case the function will use its default regular expression
     48                         syntax type.
     49 
     50   @param Result         On return, points to TRUE if String fully matches against
     51                         the regular expression Pattern using the regular expression
     52                         SyntaxType. Otherwise, points to FALSE.
     53 
     54   @param Captures       A Pointer to an array of EFI_REGEX_CAPTURE objects to receive
     55                         the captured groups in the event of a match. The full
     56                         sub-string match is put in Captures[0], and the results of N
     57                         capturing groups are put in Captures[1:N]. If Captures is
     58                         NULL, then this function doesn't allocate the memory for the
     59                         array and does not build up the elements. It only returns the
     60                         number of matching patterns in CapturesCount. If Captures is
     61                         not NULL, this function returns a pointer to an array and
     62                         builds up the elements in the array. CapturesCount is also
     63                         updated to the number of matching patterns found. It is the
     64                         caller's responsibility to free the memory pool in Captures
     65                         and in each CapturePtr in the array elements.
     66 
     67   @param CapturesCount  On output, CapturesCount is the number of matching patterns
     68                         found in String. Zero means no matching patterns were found
     69                         in the string.
     70 
     71   @retval  EFI_SUCCESS       Regex compilation and match completed successfully.
     72   @retval  EFI_DEVICE_ERROR  Regex compilation failed.
     73 
     74 **/
     75 STATIC
     76 EFI_STATUS
     77 OnigurumaMatch (
     78   IN  CHAR16                *String,
     79   IN  CHAR16                *Pattern,
     80   IN  EFI_REGEX_SYNTAX_TYPE *SyntaxType,
     81   OUT BOOLEAN               *Result,
     82   OUT EFI_REGEX_CAPTURE     **Captures,     OPTIONAL
     83   OUT UINTN                 *CapturesCount
     84   )
     85 {
     86   regex_t         *OnigRegex;
     87   OnigSyntaxType  *OnigSyntax;
     88   OnigRegion      *Region;
     89   INT32           OnigResult;
     90   OnigErrorInfo   ErrorInfo;
     91   CHAR8           ErrorMessage[ONIG_MAX_ERROR_MESSAGE_LEN];
     92   UINT32          Index;
     93   OnigUChar       *Start;
     94   EFI_STATUS      Status;
     95 
     96 
     97   Status = EFI_SUCCESS;
     98 
     99   //
    100   // Detemine the internal syntax type
    101   //
    102   OnigSyntax = ONIG_SYNTAX_DEFAULT;
    103   if (CompareGuid (SyntaxType, &gEfiRegexSyntaxTypePosixExtendedGuid)) {
    104     OnigSyntax = ONIG_SYNTAX_POSIX_EXTENDED;
    105   } else if (CompareGuid (SyntaxType, &gEfiRegexSyntaxTypePerlGuid)) {
    106     OnigSyntax = ONIG_SYNTAX_PERL;
    107   } else {
    108     DEBUG ((DEBUG_ERROR, "Unsupported regex syntax - using default\n"));
    109     return EFI_UNSUPPORTED;
    110   }
    111 
    112   //
    113   // Compile pattern
    114   //
    115   Start = (OnigUChar*)Pattern;
    116   OnigResult = onig_new (
    117                  &OnigRegex,
    118                  Start,
    119                  Start + onigenc_str_bytelen_null (CHAR16_ENCODING, Start),
    120                  ONIG_OPTION_DEFAULT,
    121                  CHAR16_ENCODING,
    122                  OnigSyntax,
    123                  &ErrorInfo
    124                  );
    125 
    126   if (OnigResult != ONIG_NORMAL) {
    127     onig_error_code_to_str (ErrorMessage, OnigResult, &ErrorInfo);
    128     DEBUG ((DEBUG_ERROR, "Regex compilation failed: %a\n", ErrorMessage));
    129     return EFI_DEVICE_ERROR;
    130   }
    131 
    132   //
    133   // Try to match
    134   //
    135   Start = (OnigUChar*)String;
    136   Region = onig_region_new ();
    137   if (Region == NULL) {
    138     onig_free (OnigRegex);
    139     return EFI_OUT_OF_RESOURCES;
    140   }
    141   OnigResult = onig_search (
    142                  OnigRegex,
    143                  Start,
    144                  Start + onigenc_str_bytelen_null (CHAR16_ENCODING, Start),
    145                  Start,
    146                  Start + onigenc_str_bytelen_null (CHAR16_ENCODING, Start),
    147                  Region,
    148                  ONIG_OPTION_NONE
    149                  );
    150 
    151   if (OnigResult >= 0) {
    152     *Result = TRUE;
    153   } else {
    154     *Result = FALSE;
    155     if (OnigResult != ONIG_MISMATCH) {
    156       onig_error_code_to_str (ErrorMessage, OnigResult);
    157       DEBUG ((DEBUG_ERROR, "Regex match failed: %a\n", ErrorMessage));
    158       onig_region_free (Region, 1);
    159       onig_free (OnigRegex);
    160       return EFI_DEVICE_ERROR;
    161     }
    162   }
    163 
    164   //
    165   // If successful, copy out the region (capture) information
    166   //
    167   if (*Result && Captures != NULL) {
    168     *CapturesCount = Region->num_regs;
    169     *Captures = AllocateZeroPool (*CapturesCount * sizeof(**Captures));
    170     if (*Captures != NULL) {
    171       for (Index = 0; Index < *CapturesCount; ++Index) {
    172         //
    173         // Region beg/end values represent bytes, not characters
    174         //
    175         (*Captures)[Index].Length = (Region->end[Index] - Region->beg[Index]) / sizeof(CHAR16);
    176         (*Captures)[Index].CapturePtr = AllocateCopyPool (
    177                                           ((*Captures)[Index].Length) * sizeof (CHAR16),
    178                                           (CHAR16*)((UINTN)String + Region->beg[Index])
    179                                           );
    180         if ((*Captures)[Index].CapturePtr == NULL) {
    181           Status = EFI_OUT_OF_RESOURCES;
    182           break;
    183         }
    184       }
    185 
    186       if (EFI_ERROR (Status)) {
    187         for (Index = 0; Index < *CapturesCount; ++Index) {
    188           if ((*Captures)[Index].CapturePtr != NULL) {
    189             FreePool ((CHAR16*)(*Captures)[Index].CapturePtr);
    190           }
    191         }
    192         FreePool (*Captures);
    193       }
    194     }
    195   }
    196 
    197   onig_region_free (Region, 1);
    198   onig_free (OnigRegex);
    199 
    200   return Status;
    201 }
    202 
    203 /**
    204   Returns information about the regular expression syntax types supported
    205   by the implementation.
    206 
    207   @param This                      A pointer to the EFI_REGULAR_EXPRESSION_PROTOCOL
    208                                    instance.
    209 
    210   @param  RegExSyntaxTypeListSize  On input, the size in bytes of RegExSyntaxTypeList.
    211                                    On output with a return code of EFI_SUCCESS, the
    212                                    size in bytes of the data returned in
    213                                    RegExSyntaxTypeList. On output with a return code
    214                                    of EFI_BUFFER_TOO_SMALL, the size of
    215                                    RegExSyntaxTypeList required to obtain the list.
    216 
    217   @param   RegExSyntaxTypeList     A caller-allocated memory buffer filled by the
    218                                    driver with one EFI_REGEX_SYNTAX_TYPE element
    219                                    for each supported Regular expression syntax
    220                                    type. The list must not change across multiple
    221                                    calls to the same driver. The first syntax
    222                                    type in the list is the default type for the
    223                                    driver.
    224 
    225   @retval EFI_SUCCESS            The regular expression syntax types list
    226                                  was returned successfully.
    227   @retval EFI_UNSUPPORTED        The service is not supported by this driver.
    228   @retval EFI_DEVICE_ERROR       The list of syntax types could not be
    229                                  retrieved due to a hardware or firmware error.
    230   @retval EFI_BUFFER_TOO_SMALL   The buffer RegExSyntaxTypeList is too small
    231                                  to hold the result.
    232   @retval EFI_INVALID_PARAMETER  RegExSyntaxTypeListSize is NULL
    233 
    234 **/
    235 EFI_STATUS
    236 EFIAPI
    237 RegularExpressionGetInfo (
    238   IN     EFI_REGULAR_EXPRESSION_PROTOCOL *This,
    239   IN OUT UINTN                           *RegExSyntaxTypeListSize,
    240   OUT    EFI_REGEX_SYNTAX_TYPE           *RegExSyntaxTypeList
    241   )
    242 {
    243   UINTN SyntaxSize;
    244   UINTN Index;
    245 
    246   if (This == NULL || RegExSyntaxTypeListSize == NULL) {
    247     return EFI_INVALID_PARAMETER;
    248   }
    249 
    250   if (*RegExSyntaxTypeListSize != 0 && RegExSyntaxTypeList == NULL) {
    251     return EFI_INVALID_PARAMETER;
    252   }
    253 
    254   SyntaxSize = ARRAY_SIZE (mSupportedSyntaxes) * sizeof(**mSupportedSyntaxes);
    255 
    256   if (*RegExSyntaxTypeListSize < SyntaxSize) {
    257     *RegExSyntaxTypeListSize = SyntaxSize;
    258     return EFI_BUFFER_TOO_SMALL;
    259   }
    260 
    261   for (Index = 0; Index < ARRAY_SIZE (mSupportedSyntaxes); ++Index) {
    262     CopyMem (&RegExSyntaxTypeList[Index], mSupportedSyntaxes[Index], sizeof(**mSupportedSyntaxes));
    263   }
    264   *RegExSyntaxTypeListSize = SyntaxSize;
    265 
    266   return EFI_SUCCESS;
    267 }
    268 
    269 /**
    270   Checks if the input string matches to the regular expression pattern.
    271 
    272   @param This          A pointer to the EFI_REGULAR_EXPRESSION_PROTOCOL instance.
    273                        Type EFI_REGULAR_EXPRESSION_PROTOCOL is defined in Section
    274                        XYZ.
    275 
    276   @param String        A pointer to a NULL terminated string to match against the
    277                        regular expression string specified by Pattern.
    278 
    279   @param Pattern       A pointer to a NULL terminated string that represents the
    280                        regular expression.
    281 
    282   @param SyntaxType    A pointer to the EFI_REGEX_SYNTAX_TYPE that identifies the
    283                        regular expression syntax type to use. May be NULL in which
    284                        case the function will use its default regular expression
    285                        syntax type.
    286 
    287   @param Result        On return, points to TRUE if String fully matches against
    288                        the regular expression Pattern using the regular expression
    289                        SyntaxType. Otherwise, points to FALSE.
    290 
    291   @param Captures      A Pointer to an array of EFI_REGEX_CAPTURE objects to receive
    292                        the captured groups in the event of a match. The full
    293                        sub-string match is put in Captures[0], and the results of N
    294                        capturing groups are put in Captures[1:N]. If Captures is
    295                        NULL, then this function doesn't allocate the memory for the
    296                        array and does not build up the elements. It only returns the
    297                        number of matching patterns in CapturesCount. If Captures is
    298                        not NULL, this function returns a pointer to an array and
    299                        builds up the elements in the array. CapturesCount is also
    300                        updated to the number of matching patterns found. It is the
    301                        caller's responsibility to free the memory pool in Captures
    302                        and in each CapturePtr in the array elements.
    303 
    304   @param CapturesCount On output, CapturesCount is the number of matching patterns
    305                        found in String. Zero means no matching patterns were found
    306                        in the string.
    307 
    308   @retval EFI_SUCCESS            The regular expression string matching
    309                                  completed successfully.
    310   @retval EFI_UNSUPPORTED        The regular expression syntax specified by
    311                                  SyntaxType is not supported by this driver.
    312   @retval EFI_DEVICE_ERROR       The regular expression string matching
    313                                  failed due to a hardware or firmware error.
    314   @retval EFI_INVALID_PARAMETER  String, Pattern, Result, or CapturesCountis
    315                                  NULL.
    316 
    317 **/
    318 EFI_STATUS
    319 EFIAPI
    320 RegularExpressionMatch (
    321   IN  EFI_REGULAR_EXPRESSION_PROTOCOL *This,
    322   IN  CHAR16                          *String,
    323   IN  CHAR16                          *Pattern,
    324   IN  EFI_REGEX_SYNTAX_TYPE           *SyntaxType, OPTIONAL
    325   OUT BOOLEAN                         *Result,
    326   OUT EFI_REGEX_CAPTURE               **Captures, OPTIONAL
    327   OUT UINTN                           *CapturesCount
    328   )
    329 {
    330   EFI_STATUS  Status;
    331   UINT32      Index;
    332   BOOLEAN     Supported;
    333 
    334   if (This == NULL || String == NULL || Pattern == NULL || Result == NULL || CapturesCount == NULL) {
    335     return EFI_INVALID_PARAMETER;
    336   }
    337 
    338   //
    339   // Figure out which syntax to use
    340   //
    341   if (SyntaxType == NULL) {
    342     SyntaxType = mSupportedSyntaxes[0];
    343   } else {
    344     Supported = FALSE;
    345     for (Index = 0; Index < ARRAY_SIZE (mSupportedSyntaxes); ++Index) {
    346       if (CompareGuid (SyntaxType, mSupportedSyntaxes[Index])) {
    347         Supported = TRUE;
    348         break;
    349       }
    350     }
    351     if (!Supported) {
    352       return EFI_UNSUPPORTED;
    353     }
    354   }
    355 
    356   Status = OnigurumaMatch (String, Pattern, SyntaxType, Result, Captures, CapturesCount);
    357 
    358   return Status;
    359 }
    360 
    361 /**
    362   Entry point for RegularExpressionDxe.
    363 
    364   @param ImageHandle     Image handle this driver.
    365   @param SystemTable     Pointer to SystemTable.
    366 
    367   @retval Status         Whether this function complete successfully.
    368 
    369 **/
    370 EFI_STATUS
    371 EFIAPI
    372 RegularExpressionDxeEntry (
    373   IN  EFI_HANDLE        ImageHandle,
    374   IN  EFI_SYSTEM_TABLE  *SystemTable
    375   )
    376 {
    377   EFI_STATUS  Status;
    378 
    379   Status = gBS->InstallMultipleProtocolInterfaces (
    380                   &ImageHandle,
    381                   &gEfiRegularExpressionProtocolGuid,
    382                   &mProtocolInstance,
    383                   NULL
    384                   );
    385 
    386   return Status;
    387 }
    388